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).
| Method | Path | Access | Description |
|---|---|---|---|
GET | /me | Read | Resolve your key's organization + library scope. |
POST | /libraries | Anonymous | Create an organization + library + API key with no account. |
GET | /:orgId/libraries | Read | List libraries in an organization. |
POST | /:orgId/libraries | Write | Create a library in an organization you have a key for. |
PATCH | /:orgId/libraries/:libraryId | Write | Rename a library. |
GET | /:orgId/libraries/:libraryId/assets | Read | List assets in a library. |
GET | /:orgId/libraries/:libraryId/assets/:assetId | Read | Get one asset by id. |
GET | /:orgId/search/assets | Read | Search assets across libraries. |
GET | /:orgId/libraries/:libraryId/tags | Read | List tags in a library. |
POST | /:orgId/libraries/:libraryId/assets | Write | Upload one or more assets. |
DELETE | /:orgId/libraries/:libraryId/assets | Write | Move assets to trash by id (soft delete). |
POST | /:orgId/libraries/:libraryId/assets/tag | Write | Apply tags to a batch of assets. |
POST | /:orgId/libraries/:libraryId/assets/untag | Write | Remove tags from a batch of assets. |
PATCH | /:orgId/libraries/:libraryId/assets/:assetId/description | Write | Replace the description on a single asset. |
POST | /:orgId/libraries/:libraryId/assets/transfer | Write | Move 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, ornullif unavailable.plan— the organization's plan (e.g.pro,hobby), ornullwhen none is set.libraries— one{ library, access }entry per library your key can act on.accessis"write"(read and write) or"read"(read-only). UseGET /librariesfor their names and counts.
Example
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 } }:
organizationIdandlibraryId— 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.emailSent—trueif the claim link was emailed. Whenfalse, surfaceclaimUrlto the user directly.
Example
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
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
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
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
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
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
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
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
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, soids.lengthequals the count inmessage.message—"Moved N assets to trash", whereNisids.length.success—truein the normal case, including a no-op where every requested id was already trashed ("Moved 0 assets to trash",ids: []). It isfalseonly when assets were moved but the library counter update failed — the assets are still trashed, butphotosCount/trashCountmay briefly drift.
Example
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
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
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
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
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"]}'