Skip to content
Masko logomasko
Docs
Documentation

Requests and responses

Use these conventions across the REST API. The endpoint reference describes each operation's exact fields and exceptions.

Base URLs

EnvironmentBase URL
Productionhttps://api.masko.ai/v1
Local Next.jshttp://localhost:3000/api/v1

Reference paths already include /v1. Combine them with the production origin https://api.masko.ai, without adding /v1 twice. Local keys and resources belong to your local environment.

Send Authorization: Bearer $MASKO_API_KEY on protected requests and Content-Type: application/json for JSON bodies. Multipart uploads use their documented content type. See API keys and workspaces.

Response envelopes

Successful JSON responses put the result in data:

{
  "data": {
    "id": "RESOURCE_ID",
    "name": "My mascot"
  }
}

Errors contain error.code, error.message, and optional error.details. Check the HTTP status before reading data; see errors and recovery.

A 204 response has no body. The public /v1/openapi.json endpoint returns the specification directly, and /v1/docs returns documentation text.

Request IDs and versions

Every response carries a Request-Id header, for example req_3f9c..., and the Masko-API-Version it used. Include the request ID when you contact support. Error bodies repeat it as error.request_id.

Pagination

List endpoints accept limit (1 to 100, default 50). Continue while meta.pagination.has_more is true by passing meta.pagination.next_cursor back as cursor. The cursor is opaque: send it exactly as returned. offset still works; send either cursor or offset, not both.

{
  "data": [],
  "meta": {
    "pagination": {
      "total": 120,
      "limit": 50,
      "offset": 0,
      "has_more": true,
      "next_cursor": "c1_eyJvIjo1MH0"
    }
  }
}

Generation receipts

Individual generation requests normally return 202 Accepted with a job receipt:

{
  "data": {
    "job_id": "JOB_ID",
    "poll_url": "/v1/jobs/JOB_ID"
  }
}

Save the receipt before waiting. Poll GET /v1/jobs/JOB_ID until completed or failed, or register a webhook. A returned file URL may be allocated before the file is ready.

Some polling URLs use the app-relative /api/v1 prefix. For the public API, construct https://api.masko.ai/v1/jobs/JOB_ID from the saved ID, as shown in the quickstart.

Long polling with ?wait=true&timeout=120 waits up to 120 seconds. Reaching that timeout returns the current job state; it does not cancel generation. Continue polling if work is still pending or processing. Derived formats can finish after the parent job: check the required assets before playback. See jobs and polling.

Batch responses contain multiple jobs. The retired character/run orchestration is not part of the Studio API. Follow each endpoint's documented job receipt; see Studio migration.

Costs and retries

Choose animation_model explicitly for new animation integrations. Standard and Premium have different costs and duration limits; omitting the field retains legacy behavior. See credits and costs.

A client timeout does not cancel an accepted generation. Standard authenticated resource POST endpoints support Idempotency-Key; /v1/auth/* and /v1/admin/* do not use this middleware. Send a unique value (a UUID is ideal, up to 255 characters) and persist it with the request before sending:

curl -X POST https://api.masko.ai/v1/mascots/MASCOT_ID/generate \
  -H "Authorization: Bearer masko_YOUR_API_KEY" \
  -H "Idempotency-Key: 5f2c0b1e-8d3a-4c6f-9b2e-1a7d4e9c0f11" \
  -H "Content-Type: application/json" \
  -d '{"type": "image", "name": "Wave", "image_prompt": "waving hello"}'
  • Keys belong to your account and bind the credential workspace, effective API version, URL, content type and exact body bytes. Keep all of these unchanged on retries, including the boundary and bytes of multipart uploads. Reusing a key with different inputs returns 409 idempotency_key_reused.
  • Once execution starts, its response is stored for 24 hours after completion, including 5xx responses. An authorized retry returns the stored status and body with Idempotent-Replayed: true, without running or charging again. Each HTTP attempt gets its own Request-Id and error request_id.
  • Replays still require a valid write credential and current access to the resources checked by the original operation. Revoked access or a resource moved outside your workspace returns 403.
  • A running request returns 409 idempotency_request_in_progress. If saving its outcome fails, the first response is 503 idempotency_persistence_failed and subsequent attempts may return that 409. An unconfirmed execution stays blocked even after 24 hours. Retry only with the same key; inspect the saved job or contact support if the conflict persists.
  • A stored 500 does not prove that no write occurred. Do not switch keys to retry a failed operation without checking its outcome. After a completed receipt expires, reusing its key starts a new request.

Without the header, every POST runs as a new request.