Raster

Endpoints

Every REST route in the Raster API, with parameters, responses, and examples.

Every endpoint lives under https://api.raster.app/organizations/:organizationId/.... The :organizationId segment is your organization slug. Library-scoped endpoints add /libraries/:libraryId. Every request requires the Authorization: Bearer <API_KEY> and Api-Version: 2026-05-20 headers (see Authentication).

MethodPathAccessDescription
GET/meReadResolve your key's organization + library scope.
POST/librariesAnonymousCreate an organization + library + API key with no account.
GET/:orgId/librariesReadList libraries in an organization.
POST/:orgId/librariesWriteCreate a library in an organization you have a key for.
PATCH/:orgId/libraries/:libraryIdWriteRename a library.
GET/:orgId/libraries/:libraryId/assetsReadList assets in a library.
GET/:orgId/libraries/:libraryId/assets/:assetIdReadGet one asset by id.
GET/:orgId/search/assetsReadSearch assets across libraries.
GET/:orgId/libraries/:libraryId/tagsReadList tags in a library.
POST/:orgId/libraries/:libraryId/assetsWriteUpload one or more assets.
DELETE/:orgId/libraries/:libraryId/assetsWriteMove assets to trash by id (soft delete).
POST/:orgId/libraries/:libraryId/assets/tagWriteApply tags to a batch of assets.
POST/:orgId/libraries/:libraryId/assets/untagWriteRemove tags from a batch of assets.
PATCH/:orgId/libraries/:libraryId/assets/:assetId/descriptionWriteReplace the description on a single asset.
POST/:orgId/libraries/:libraryId/assets/transferWriteMove a batch of assets to another library.

GET /me

Resolves the organization and libraries your API key can act on. Call this first when you hold only a key: it returns the organizationId (and authorized library ids) that every other endpoint needs as a path segment. The endpoint lives at /me and resolves the organization from your key. Send the Authorization: Bearer and Api-Version headers as on every authenticated request.

Returns

{ data: { organizationId, organizationName, plan, libraries } }:

  • organizationId — the organization your key belongs to; pass it to every org-scoped endpoint.
  • organizationName — the organization's display name, or null if unavailable.
  • plan — the organization's plan (e.g. pro, hobby), or null when none is set.
  • libraries — one { library, access } entry per library your key can act on. access is "write" (read and write) or "read" (read-only). Use GET /libraries for their names and counts.

Example

Terminal
curl --request GET \
  --header 'Authorization: Bearer <API_KEY>' \
  --header 'Api-Version: 2026-05-20' \
  --url 'https://api.raster.app/me'

Response:

{
  "data": {
    "organizationId": "acme-co",
    "organizationName": "Acme Co",
    "plan": "pro",
    "libraries": [
      { "library": "marketing", "access": "write" },
      { "library": "product-shots", "access": "write" },
      { "library": "archive", "access": "read" }
    ]
  }
}

POST /libraries

Creates a brand-new organization — plus a starter library and API key to use it — for a caller with no Raster account and no API key yet. A client (typically an AI agent) calls it with a person's email, gets back a ready-to-use key, and starts uploading right away. The new library is held for 30 days so the person can claim it — they click the emailed link to fold the library and everything in it into a real Raster account. Anything left unclaimed when the window closes is removed.

The same flow is available over MCP as the create_organization tool. To create a library inside an organization you already have a key for, use POST /:orgId/libraries instead.

POST to https://api.raster.app/libraries. The endpoint is anonymous — it mints the key, so send it with no Authorization header. Include the Api-Version header and read the { data } / { error } envelope as on every other request. A per-IP rate limit (429) and the per-email quota below bound abuse.

Parameters

A JSON request body:

Prop

Type

Returns

{ data: { organizationId, libraryId, apiKey, claimUrl, expiresAt, emailSent } }:

  • organizationId and libraryId — identify the new library; pass both to every later asset call, e.g. POST /:orgId/libraries/:libraryId/assets.
  • apiKey — the Bearer token for those calls. Returned once — persist it immediately.
  • claimUrl — the link the user opens to claim the library into a Raster account.
  • expiresAt — ISO 8601 timestamp for when the claim window closes.
  • emailSenttrue if the claim link was emailed. When false, surface claimUrl to the user directly.

Example

Terminal
curl --request POST \
  --header 'Api-Version: 2026-05-20' \
  --header 'Content-Type: application/json' \
  --url 'https://api.raster.app/libraries' \
  --data '{"email":"[email protected]","name":"Sample library"}'

Response:

{
  "data": {
    "organizationId": "k3m9x7p2qar8zt",
    "libraryId": "b7n2w4j8x1c5dq",
    "apiKey": "rk_…",
    "claimUrl": "https://raster.app/claim/…",
    "expiresAt": "2026-07-03T00:00:00.000Z",
    "emailSent": true
  }
}

Use the returned apiKey as the Authorization: Bearer token and the organizationId + libraryId as the target for every subsequent call — upload, list, search, tag, and the rest of the org-scoped surface.

GET /libraries

Lists the libraries in an organization that your API key can reach.

Parameters

Prop

Type

Returns

{ data: Library[] } — see Library.

Example

Terminal
curl --request GET \
  --header 'Authorization: Bearer <API_KEY>' \
  --header 'Api-Version: 2026-05-20' \
  --url 'https://api.raster.app/organizations/acme-co/libraries?page=1&pageSize=20'

POST /:orgId/libraries

Creates a new library inside an organization you already have an API key for. The new library is added to your key's allowlist (so the same key can upload to it immediately) and is shown to your whole team in the Raster app. Because the new library is granted to your key, the key must have write access — a read-only key cannot create libraries. To start a new organization from scratch with no account, use the anonymous POST /libraries.

The same flow is available over MCP as the create_library tool.

Parameters

Prop

Type

Returns

201 Created with { data: Library } — see Library. A new library has zeroed counters and no tags. On a free (hobby) plan at the library cap, returns 400 LIBRARY_LIMIT_EXCEEDED. A read-only key returns 403 API_KEY_READ_ONLY.

Example

Terminal
curl --request POST \
  --header 'Authorization: Bearer <API_KEY>' \
  --header 'Api-Version: 2026-05-20' \
  --header 'Content-Type: application/json' \
  --url 'https://api.raster.app/organizations/acme-co/libraries' \
  --data '{"name":"Marketing","slug":"marketing"}'

PATCH /libraries/:libraryId

Renames a library your API key has access to. Updates the library name everywhere it's shown, including each team member's view. The URL slug is not changed.

The same flow is available over MCP as the rename_library tool.

Parameters

Prop

Type

Returns

{ data: Library } — the updated Library. A key not authorized for the library, or a missing library, returns 404.

Example

Terminal
curl --request PATCH \
  --header 'Authorization: Bearer <API_KEY>' \
  --header 'Api-Version: 2026-05-20' \
  --header 'Content-Type: application/json' \
  --url 'https://api.raster.app/organizations/acme-co/libraries/marketing' \
  --data '{"name":"Marketing 2026"}'

GET /libraries/:libraryId/assets/:assetId

Fetches a single asset by id — the same Asset shape GET /libraries/:libraryId/assets returns, for one asset. Use it to read one asset's url, tags, description, and dimensions without paging the list. The :assetId is the id returned by list, search, or upload.

Parameters

Prop

Type

Returns

{ data: Asset } — see Asset. Returns 404 when the asset does not exist, belongs to a different library, or is trashed (the same 404 for all three, so it never leaks an asset outside your library).

Example

Terminal
curl --request GET \
  --header 'Authorization: Bearer <API_KEY>' \
  --header 'Api-Version: 2026-05-20' \
  --url 'https://api.raster.app/organizations/acme-co/libraries/marketing/assets/k3m9x7p2qar8zt'

GET /libraries/:libraryId/assets

Lists assets in a library, paginated and optionally filtered by tag.

Parameters

Prop

Type

Returns

{ data: Asset[] } — see Asset.

Example

Terminal
curl --request GET \
  --header 'Authorization: Bearer <API_KEY>' \
  --header 'Api-Version: 2026-05-20' \
  --url 'https://api.raster.app/organizations/acme-co/libraries/barcelona/assets?page=1&pageSize=20&tags=landscape,nature'

GET /search/assets

Searches assets across the libraries your API key authorizes, returning relevance-ranked hits with optional highlighted snippets. This endpoint is organization-scoped — pass libraries to narrow to a subset of authorized libraries, or omit it to search every library the key can reach.

Parameters

Prop

Type

Returns

{ data: SearchResult } — see SearchResult and SearchHit.

Example

Terminal
curl --request GET \
  --header 'Authorization: Bearer <API_KEY>' \
  --header 'Api-Version: 2026-05-20' \
  --url 'https://api.raster.app/organizations/acme-co/search/assets?q=sunset&libraries=barcelona,lisbon&page=1&pageSize=10'

Asking for an unauthorized library fails the whole request with 404 API_KEY_NOT_AUTHORIZED_FOR_LIBRARY — the request is rejected before any search runs and no partial results are returned. To search every library the key authorizes, omit libraries entirely.

GET /libraries/:libraryId/tags

Lists the tags in a library, with their hit counts.

Parameters

Prop

Type

Returns

{ data: Tag[] } — see Tag.

Example

Terminal
curl --request GET \
  --header 'Authorization: Bearer <API_KEY>' \
  --header 'Api-Version: 2026-05-20' \
  --url 'https://api.raster.app/organizations/acme-co/libraries/barcelona/tags?limit=100'

POST /libraries/:libraryId/assets

Uploads one or more files to a library. The request body is multipart/form-data with a repeatable files field.

Parameters

Prop

Type

Returns

{ data: { responseText: string, assets: Asset[] } }. Each entry is the same Asset shape GET /assets returns — upload and read share one type. The url field is the permanent CDN URL and is populated immediately, so the value never changes. The upload-time response also includes id, name, libraryId, tags, contentType, and created. Fields computed asynchronously — width, height, size, blurhash, thumbUrl, thumbHighUrl, thumbUrlBlurred, views, type, description, updated, uploadedBy — are returned as null at upload time and populate once processing finishes (typically within seconds). Re-read the asset via GET /assets to pick them up.

Example

Terminal
curl --request POST \
  --header 'Authorization: Bearer <API_KEY>' \
  --header 'Api-Version: 2026-05-20' \
  --url 'https://api.raster.app/organizations/acme-co/libraries/barcelona/assets' \
  --form 'files=@/path/to/photo-1.jpg' \
  --form 'files=@/path/to/photo-2.png'

The multipart field name must be files. Anything else is rejected with 400 and BAD_USER_INPUT. Per-file size and count limits map to 413 PAYLOAD_TOO_LARGE and 400 MAX_ASSETS_EXCEEDED respectively — see the Errors reference.

DELETE /libraries/:libraryId/assets

Moves assets to trash by id, in batches — a soft delete that matches the Raster app. The assets leave GET /assets and search immediately (both only return live assets), stay recoverable from trash, and are permanently removed after 30 days. Emptying trash for good stays in the app.

Parameters

Prop

Type

Returns

{ data: { success: boolean, message: string, ids: string[] } }:

  • ids — the asset ids actually moved to trash by this call. Ids already in trash (an idempotent retry) or not in the library are skipped, so ids.length equals the count in message.
  • message"Moved N assets to trash", where N is ids.length.
  • successtrue in the normal case, including a no-op where every requested id was already trashed ("Moved 0 assets to trash", ids: []). It is false only when assets were moved but the library counter update failed — the assets are still trashed, but photosCount / trashCount may briefly drift.

Example

Terminal
curl --request DELETE \
  --header 'Authorization: Bearer <API_KEY>' \
  --header 'Api-Version: 2026-05-20' \
  --header 'Content-Type: application/json' \
  --url 'https://api.raster.app/organizations/acme-co/libraries/barcelona/assets' \
  --data '{"ids":["abc123","def456"]}'

POST /libraries/:libraryId/assets/tag

Applies one or more tags to a batch of assets in a single library. Idempotent on (asset, tag) pairs the asset already carries — re-running the same call is a no-op for those pairs.

Parameters

Prop

Type

Returns

{ data: { taggedCount: number } }. taggedCount is the number of (asset, tag) pairs that actually mutated state — pairs the asset already carried are counted as silent skips and not surfaced. To check "did every pair I asked for land?", compare taggedCount against assetIds.length × tags.length.

Example

Terminal
curl --request POST \
  --header 'Authorization: Bearer <API_KEY>' \
  --header 'Api-Version: 2026-05-20' \
  --header 'Content-Type: application/json' \
  --url 'https://api.raster.app/organizations/acme-co/libraries/barcelona/assets/tag' \
  --data '{"assetIds":["abc123","def456"],"tags":["sunset","landscape"]}'

POST /libraries/:libraryId/assets/untag

Removes one or more tags from a batch of assets in a single library. Symmetric with /assets/tag — idempotent on (asset, tag) pairs the asset doesn't carry.

Parameters

Prop

Type

Returns

{ data: { untaggedCount: number } }. untaggedCount is the number of (asset, tag) pairs that actually mutated state.

Example

Terminal
curl --request POST \
  --header 'Authorization: Bearer <API_KEY>' \
  --header 'Api-Version: 2026-05-20' \
  --header 'Content-Type: application/json' \
  --url 'https://api.raster.app/organizations/acme-co/libraries/barcelona/assets/untag' \
  --data '{"assetIds":["abc123"],"tags":["landscape"]}'

PATCH /libraries/:libraryId/assets/:assetId/description

Replaces the description on a single asset. The value lands on the doc verbatim — no trim, no AI rewrite. Pass an empty string to clear the field.

Parameters

Prop

Type

Returns

{ data: { assetId: string, description: string } } — echoes the written asset id and the description that landed on the asset, so clients confirm without an extra read.

Example

Terminal
curl --request PATCH \
  --header 'Authorization: Bearer <API_KEY>' \
  --header 'Api-Version: 2026-05-20' \
  --header 'Content-Type: application/json' \
  --url 'https://api.raster.app/organizations/acme-co/libraries/barcelona/assets/abc123/description' \
  --data '{"description":"Golden hour over the Mediterranean."}'

POST /libraries/:libraryId/assets/transfer

Moves a batch of assets from one library to another within the same organization. The URL's :libraryId is the source library; the body names the target. Cross-organization transfer is rejected with 400 BAD_USER_INPUT. Same source and target resolves to a no-op (transferredCount: 0) without any writes.

Parameters

Prop

Type

Returns

{ data: { transferredCount: number, sourceLibraryId: string, targetLibraryId: string } }. Source and target are echoed so clients confirm both ends without an extra fetch.

Example

Terminal
curl --request POST \
  --header 'Authorization: Bearer <API_KEY>' \
  --header 'Api-Version: 2026-05-20' \
  --header 'Content-Type: application/json' \
  --url 'https://api.raster.app/organizations/acme-co/libraries/barcelona/assets/transfer' \
  --data '{"targetLibraryId":"lisbon","assetIds":["abc123","def456"]}'

On this page