For AI agents: this page is also available as Markdown at https://docs.refabric.com/api-reference/platform/conventions.md, and the index of every page is https://docs.refabric.com/llms.txt.

Platform API

Conventions

Rules that hold across every endpoint.

Requests

  • JSON bodies, Content-Type: application/json (uploads may use multipart/form-data).
  • Field names are snake_case.
  • A task's input takes exactly the fields in its schema (GET /v1/tasks/{name}). Any other field — a misspelled name, or one the server fills itself — is refused with 422 field_not_accepted, and field names it, so a typo shows up on the first call. (This rule is for the task input; query parameters work as each endpoint documents them.) Known fields are validated — a wrong type, a value out of range or a missing required field is a 422 naming the field.

Pagination

List endpoints use cursors.

GET /v1/jobs?limit=50
{ "items": [ … ], "has_more": true, "next_cursor": "AXsiZiI6IjQ0MTM2ZmEzNTVi…" }
  • limit: page size (default and maximum per endpoint in the OpenAPI spec).
  • has_more says whether another page follows. While it is true, pass cursor=<next_cursor> for the next page. On the last page has_more is false and next_cursor is absent.
  • Cursors are opaque; do not build or parse them. They may expire — restart the listing if one is refused.
  • Order is newest first unless an endpoint says otherwise (a job result's files are in the order the task documents — Jobs).
def all_items(session, url, **params):
    cursor = None
    while True:
        page = session.get(url, params={**params, **({"cursor": cursor} if cursor else {})}).json()
        yield from page["items"]
        if not page["has_more"]:
            return
        cursor = page["next_cursor"]

Time

ISO-8601 in UTC with a Z suffix: 2026-09-28T10:00:00Z. Fractional seconds may appear. Durations in a body are integer milliseconds, and their field says so (duration_ms, wait_ms, run_ms); a setting whose name ends in _seconds (limits.*.max_seconds of GET /v1/meta, grace_period_seconds) says seconds the same way. Header values stay in seconds (Retry-After, Prefer: wait=N), and webhook X-Refabric-Timestamp is Unix seconds, because it is part of a signed message.

Ids

All ids and references are opaque strings (j_…, art:…, file:…, req_…, key_…). Do not parse them, assume a length, or build them. Compare them as exact strings.

Enums

Every closed option in an input schema lists its allowed values, each with a description.

  • Inputs: only the listed values are accepted.
  • Outputs: new values may appear at any time (for example a new job status or error type). Your code must tolerate unknown values — treat them as "other", not as an error.

Nulls and missing fields

  • In responses, a field that has no value is present with null, unless the schema marks it optional.
  • New response fields may be added at any time; ignore fields you do not know.
  • In requests, omitting an optional field and sending null mean the same thing: use the default.

Numbers and money

Credits are whole numbers (integers) in the account's credit unit, sent as integers. They appear in X-Refabric-Credits, the estimate response, and account endpoints — never inside job results. Prices per task: Pricing.

Headers

HeaderDirectionMeaning
Authorization / x-api-keyrequestAuthentication
Idempotency-KeyrequestIdempotency
X-Request-IDbothyour correlation id (optional) inbound; our request_id always outbound
X-Client-Request-IDresponseyour X-Request-ID, echoed when it was a valid one
Prefer: wait=Nrequestsync mode
X-Refabric-Start-Timeoutrequeststart deadline
Refabric-Versionrequestdated version pin
X-Refabric-Credits, X-Refabric-Credit-Typeresponseon the submit answer (POST /v1/tasks/{name}) only, and only when the task costs credits: the credits held, and their credit_type (the same value /estimate and GET /v1/pricing answer)
X-Refabric-Error-Typeresponsethe error.type of an error response
X-Refabric-Start-Timeout-Typeresponseuser when a job failed its start deadline
X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, Retry-AfterresponseRate limits

Every response, success or error, carries X-Request-ID — always OUR id (req_…). If you send X-Request-ID (at most 128 characters of A-Z a-z 0-9 . _ : -), we log it next to ours and echo it back as X-Client-Request-ID; anything else is ignored, never refused.