Skip to content
SBDocs

Providers · Guides

Run your own endpoint

What Sushibelt sends your API in each of the three families, what it expects back, and how it counts usage.

Before you start
  • An API you run, reachable over HTTPS.
You'll end with
An endpoint that answers Sushibelt's requests the way a declaration describes.

After a handover, Sushibelt sends customers' runs to the endpoint you declared. This guide says what arrives at that endpoint, what Sushibelt expects back, and how it counts usage — so you can check your API against it before you declare. The exact fields are in the transport reference.

The three families#

A transport belongs to one of three families. For a claim, use the family Sushibelt already uses for your provider: the requests customers' runs make are built for it.

Transport families
FamilyDescription
openai-compatibleAn OpenAI-style chat API. One POST {baseUrl}/chat/completions; the text comes back in the answer. For language models.
sync-restOne JSON POST; the file comes back in the answer — a link, base64, or the file itself. For fast image, audio or 3D calls.
submit-pollA JSON POST starts a task and answers with its id; Sushibelt then asks for the task until it succeeds or fails. For work that takes longer than one request.

Authentication#

Every request carries a key in one of two ways, which you choose with auth:

  • { "scheme": "bearer" } sends Authorization: Bearer KEY.
  • { "scheme": "header", "header": "x-api-key" } sends x-api-key: KEY — any header name you give.

openai-compatible always uses Bearer. The key is the one you declared — unless the customer has added their own key for your provider, in which case their key is sent instead. Your endpoint should accept both.

What each request carries#

openai-compatible#

POST {baseUrl}/chat/completions with a fixed body. The model is the one the customer picked on the step. If the step names none and Sushibelt has no default model for your provider, the step fails before it reaches you.

Request body Sushibelt sendsJSON
{
  "model": "your-model-id",
  "messages": [
    {
      "role": "system",
      "content": "The system prompt, when the step has one."
    },
    {
      "role": "user",
      "content": "The customer's prompt."
    }
  ],
  "max_tokens": 1024,
  "temperature": 0.7
}

Sushibelt reads the text from choices[0].message.content. An answer without a choices list fails the step. On an error status, the step fails with your error.message (or message).

Answer Sushibelt expectsJSON
{
  "choices": [
    {
      "message": {
        "content": "The text the step outputs."
      }
    }
  ],
  "usage": {
    "prompt_tokens": 18,
    "completion_tokens": 42
  }
}

sync-rest and submit-poll#

The body is built for each model from its capability descriptor: which of the step's settings go in which field, with which fixed values. Sushibelt sends it as JSON with a POST to the endpoint the descriptor names. That endpoint must be on the same origin as your baseUrl; Sushibelt will not send your key anywhere else. Each model can use its own path.

Example request body, built from a descriptorJSON
{
  "prompt": "a stone well, low poly, game asset",
  "num_inference_steps": 28,
  "size": "1024x1024",
  "response_format": "url"
}
  • Only settings the descriptor declares are sent; anything else on the step is dropped.
  • Numbers are held to the descriptor's minimum and maximum before they are sent.
  • Files from earlier steps — an image, a mesh, audio — arrive as URLs your API downloads, in the fields the descriptor names.
  • When the result is the file itself (bytes), Sushibelt also sends Accept with the file's type.

For a provider Sushibelt already sells, Sushibelt keeps its models' descriptors. Before a handover it checks that your endpoint can take the request for every one of them.

Where the result is#

Your transport's delivery says what the output is (produces: one of images, model_mesh, audio) and where to find it (result). A result is one of 3 kinds:

Result kinds
KindDescription
urlThe answer holds a link to the file, at path.
base64The answer holds the file as base64, at path, with its mime type. Sushibelt decodes and stores it. Sync-rest only in practice: see below.
bytesThe answer body is the file, of type mime. Sync-rest only.

A path is a dotted path into the JSON answer; a number picks an array item, so data.0.url is the url of the first item in data. Give a list of paths to try in order — ["model_urls.glb", "model_urls.fbx"] — and the first that holds text is used. If none does, the step fails.

Submit and poll#

The task id#

Your submit answer must be JSON and carry the task id. Declare where with taskIdPath, such as data.task_id. Without it, Sushibelt tries `id`, `task_id`, `data.id`, `data.task_id`, `result.id`, `result.task_id`, in that order.

Submit answerJSON
{
  "data": {
    "task_id": "abc123"
  }
}

Polling#

Sushibelt asks for the task at {baseUrl}{pollPath}/{taskId} — your pollPath, a slash, then the id — as a GET with the same key header. The answer must be JSON.

  • poll.statusPath points at the task's status (use "" if the whole answer is the status). A status that is not text is compared as its JSON text, so a numeric status 2 matches "2".
  • A status in poll.success means done: Sushibelt reads the result from this same answer.
  • A status in poll.failure fails the step, with the message at poll.errorPath if you declare one.
  • Any other status means still running, and Sushibelt asks again later.
Poll answer for a finished taskJSON
{
  "data": {
    "status": "success",
    "output": {
      "model": "https://files.example.com/abc123.glb"
    }
  }
}

Warning: use a link for a polled result

A submit-and-poll result must be url: a polled result is read as a link, so a declaration naming base64 or bytes there is refused.

How Sushibelt counts usage#

Sushibelt does not read a usage count from your answers. Each call to your endpoint counts as one unit, in every family, and is charged at your price for one unit. That is why a provider you run is priced per run or per step (see pricing units).

The exception is a provider Sushibelt prices from its own published rates. For those, Sushibelt works out each run's real cost itself — for chat, from the usage token counts in your answer, capped by what was sent and by max_tokens — and the listing stays priced in usd_micro.

What your endpoint receives#

  • Customers' prompts and settings, and links to their input files.
  • A customer's own key, when they bring one.
  • Probe requests from Sushibelt, which look like real runs (see the probe reference).

The seller agreement says what you may do with customers' data and keys. Your storefront's Customers page shows volume, node types and error rate across your customers.

Next steps