API ReferenceEndpointsMedia

Media

Media assets — product images, brand logos, variant photos. Endpoints here issue presigned upload URLs, list/move/delete assets, and manage folders. Storage backend is configurable (S3, R2, local).

Every operation below is on the public API surface — both paths are under /v1 and take Authorization: Bearer brainerce_*.

POST /v1/media takes multipart/form-data with either a binary file part (≤ 10 MB) or a sourceUrl field to ingest a remote image, fetched server-side through the SSRF-safe downloader. On this surface the bytes go through that one endpoint — there is no presigned-upload or folder-management operation in the public API. (The dashboard’s own media screens use a separate internal flow that is not part of the public contract and is not documented here.)

List media library assets

GET
/v1/media
AuthorizationBearer <token>

Admin API key (server-to-server). Issue via the dashboard at Settings → Authentication → API Keys. Plain-text key is shown once — store in a secret manager. Format: Authorization: Bearer brainerce_xxxxxxxxx.

In: header

Query Parameters

page?number
limit?number
search?string

Filename / name search

curl -X GET "https://api.brainerce.com/api/v1/media?page=0&limit=0&search=string"
{
  "data": [
    {
      "id": "string",
      "url": "string",
      "key": "string",
      "thumbnailUrl": "string",
      "mimeType": "image/webp",
      "width": 0,
      "height": 0,
      "size": 0,
      "name": "string",
      "alt": "string",
      "createdAt": "2019-08-24T14:15:22Z"
    }
  ],
  "meta": {
    "page": 1,
    "limit": 20,
    "total": 137,
    "totalPages": 7
  }
}

{
  "statusCode": 401,
  "code": "UNAUTHORIZED",
  "message": "Invalid or expired credential",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/media"
}

{
  "statusCode": 403,
  "code": "INSUFFICIENT_SCOPE",
  "message": "API key does not have the required scope: products:write",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/media"
}

Upload or ingest a media asset

Send multipart/form-data with either a binary file part (≤10 MB) or a sourceUrl field to ingest a remote image by URL (fetched server-side through the SSRF-safe downloader). Returns the created asset.

POST
/v1/media
AuthorizationBearer <token>

Admin API key (server-to-server). Issue via the dashboard at Settings → Authentication → API Keys. Plain-text key is shown once — store in a secret manager. Format: Authorization: Bearer brainerce_xxxxxxxxx.

In: header

file?string

Binary file (≤10 MB)

sourceUrl?string

Remote http(s) image URL to ingest (alternative to file)

curl -X POST "https://api.brainerce.com/api/v1/media"
{
  "id": "string",
  "url": "string",
  "key": "string",
  "thumbnailUrl": "string",
  "mimeType": "image/webp",
  "width": 0,
  "height": 0,
  "size": 0,
  "name": "string",
  "alt": "string",
  "createdAt": "2019-08-24T14:15:22Z"
}

{
  "statusCode": 400,
  "code": "VALIDATION_FAILED",
  "message": "name should not be empty, price must be a positive number",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/media"
}

{
  "statusCode": 401,
  "code": "UNAUTHORIZED",
  "message": "Invalid or expired credential",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/media"
}

{
  "statusCode": 403,
  "code": "INSUFFICIENT_SCOPE",
  "message": "API key does not have the required scope: products:write",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/media"
}

{
  "statusCode": 429,
  "code": "RATE_LIMITED",
  "message": "Too many requests",
  "details": {
    "retryAfterSeconds": 12
  },
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/media"
}

Get a media asset by ID

GET
/v1/media/{id}
AuthorizationBearer <token>

Admin API key (server-to-server). Issue via the dashboard at Settings → Authentication → API Keys. Plain-text key is shown once — store in a secret manager. Format: Authorization: Bearer brainerce_xxxxxxxxx.

In: header

Path Parameters

idstring

Asset ID

curl -X GET "https://api.brainerce.com/api/v1/media/string"
{
  "id": "string",
  "url": "string",
  "key": "string",
  "thumbnailUrl": "string",
  "mimeType": "image/webp",
  "width": 0,
  "height": 0,
  "size": 0,
  "name": "string",
  "alt": "string",
  "createdAt": "2019-08-24T14:15:22Z"
}

{
  "statusCode": 401,
  "code": "UNAUTHORIZED",
  "message": "Invalid or expired credential",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/media/{id}"
}

{
  "statusCode": 403,
  "code": "INSUFFICIENT_SCOPE",
  "message": "API key does not have the required scope: products:write",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/media/{id}"
}

{
  "statusCode": 404,
  "code": "RESOURCE_NOT_FOUND",
  "message": "Resource not found",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/media/{id}"
}

Update media asset metadata

Update the asset’s alt text and/or display name. Supports Idempotency-Key.

PATCH
/v1/media/{id}
AuthorizationBearer <token>

Admin API key (server-to-server). Issue via the dashboard at Settings → Authentication → API Keys. Plain-text key is shown once — store in a secret manager. Format: Authorization: Bearer brainerce_xxxxxxxxx.

In: header

Path Parameters

idstring

Asset ID

Header Parameters

Idempotency-Key?string

Client-supplied key (a UUID v4 is the recommended form, max 255 characters) that makes this mutation safe to retry.

  • Replay window: 24 hours. The first response for a key is cached; a retry inside the window with the same request body returns the original status and body without re-running the handler.
  • Reusing a key with a different body returns 409 Conflict with code: "IDEMPOTENCY_KEY_REUSED". The request fingerprint (method + path + body hash) is compared against the stored one; a mismatch is refused rather than served the old response.
  • Keys are scoped to the calling credential and store — two API keys may safely use the same key value.
  • Error responses are cached too, so a retry of a request that failed validation returns the same 400 immediately.
  • Sending this header on a GET returns 400 with code: "IDEMPOTENCY_KEY_NOT_SUPPORTED" — GETs are already idempotent.
  • Support is per-route and this parameter is the authoritative signal: a key sent to a route that does not declare it is accepted and silently ignored.

See /docs/api/idempotency.

Lengthlength <= 255
alt?string

Accessibility alt text for the asset.

name?string

Display name / title of the asset in the media library.

curl -X PATCH "https://api.brainerce.com/api/v1/media/string" \  -H "Idempotency-Key: string" \  -H "Content-Type: application/json" \  -d '{}'
{
  "id": "string",
  "url": "string",
  "key": "string",
  "thumbnailUrl": "string",
  "mimeType": "image/webp",
  "width": 0,
  "height": 0,
  "size": 0,
  "name": "string",
  "alt": "string",
  "createdAt": "2019-08-24T14:15:22Z"
}

{
  "statusCode": 400,
  "code": "VALIDATION_FAILED",
  "message": "name should not be empty, price must be a positive number",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/media/{id}"
}

{
  "statusCode": 401,
  "code": "UNAUTHORIZED",
  "message": "Invalid or expired credential",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/media/{id}"
}

{
  "statusCode": 403,
  "code": "INSUFFICIENT_SCOPE",
  "message": "API key does not have the required scope: products:write",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/media/{id}"
}

{
  "statusCode": 404,
  "code": "RESOURCE_NOT_FOUND",
  "message": "Resource not found",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/media/{id}"
}

Delete a media asset

Soft-deletes the asset and removes its key from every product/variant/category/brand/store/modifier that referenced it. Supports Idempotency-Key.

DELETE
/v1/media/{id}
AuthorizationBearer <token>

Admin API key (server-to-server). Issue via the dashboard at Settings → Authentication → API Keys. Plain-text key is shown once — store in a secret manager. Format: Authorization: Bearer brainerce_xxxxxxxxx.

In: header

Path Parameters

idstring

Asset ID

Header Parameters

Idempotency-Key?string

Client-supplied key (a UUID v4 is the recommended form, max 255 characters) that makes this mutation safe to retry.

  • Replay window: 24 hours. The first response for a key is cached; a retry inside the window with the same request body returns the original status and body without re-running the handler.
  • Reusing a key with a different body returns 409 Conflict with code: "IDEMPOTENCY_KEY_REUSED". The request fingerprint (method + path + body hash) is compared against the stored one; a mismatch is refused rather than served the old response.
  • Keys are scoped to the calling credential and store — two API keys may safely use the same key value.
  • Error responses are cached too, so a retry of a request that failed validation returns the same 400 immediately.
  • Sending this header on a GET returns 400 with code: "IDEMPOTENCY_KEY_NOT_SUPPORTED" — GETs are already idempotent.
  • Support is per-route and this parameter is the authoritative signal: a key sent to a route that does not declare it is accepted and silently ignored.

See /docs/api/idempotency.

Lengthlength <= 255
curl -X DELETE "https://api.brainerce.com/api/v1/media/string" \  -H "Idempotency-Key: string"
{
  "success": true
}

{
  "statusCode": 401,
  "code": "UNAUTHORIZED",
  "message": "Invalid or expired credential",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/media/{id}"
}

{
  "statusCode": 403,
  "code": "INSUFFICIENT_SCOPE",
  "message": "API key does not have the required scope: products:write",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/media/{id}"
}

{
  "statusCode": 404,
  "code": "RESOURCE_NOT_FOUND",
  "message": "Resource not found",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/media/{id}"
}

On this page

No Headings