Skip to content
Foldbun StackDocs
中Get an API keyComing soon

Overview

Pay-per-use computer-vision model API (segmentation, OCR, document parsing, embeddings, background removal). Draft v1: synchronous calls only; asynchronous jobs and webhooks come later.

Request id. Every response (errors included) carries X-Request-Id, a random 16-hex-character id generated by the server (a header sent by the client is ignored). Quote it when contacting support.

Auth. Authorization: Bearer fbs_... (API key created in the console). A key may carry model:<id> scopes; when it has any, it can only call those models.

Money. Amounts are credits, written as JSON numbers with up to 6 decimals (the unit is a micro-credit, so they are exact). Top-ups are credited at US$1 = 1,000 credits. cost is what this call charged, balance is the account balance after it. Failed calls cost 0.

Images. Every image input is {"id": "img_<sha256>"}, {"base64": "..."} or {"url": "https://..."} (url is reserved: later, today it answers 400 unsupported). Uploaded images are sanitized by Stack, and an inline image.base64 behaves like an upload: metadata (EXIF, XMP, comments, thumbnails) and any data appended after the image are removed at upload; the pixels are not changed or re-encoded. The image itself is kept for at most 7 days (below). It is never forwarded to GPU nodes, which only receive per-model resized copies generated by Stack. All coordinates in requests and responses are pixels of the oriented original: the uploaded image with its EXIF orientation applied, at its full size. Its size is returned as image.width / image.height (and by POST /v1/images); there is no resizing and no short-side limit beyond the input limits below. Boxes and polygons are always in image pixels; a mask can be smaller than the image: it carries its own size in mask.size, and clients scale by it (see options.maskSize). img_<sha256> is the SHA-256 of the sanitized bytes (not of the uploaded file). A handle is valid only inside the account that uploaded it, and is kept on a best-effort basis and deleted after at most 7 days, counted from when the account first stored it (earlier under capacity pressure, least recently used first; no minimum retention): on 404 image_not_found, upload again. If the image storage is temporarily unavailable, a call answers 503 unavailable with Retry-After. A file that passes the upload checks but cannot be decoded is 400 invalid_image on its first use; the handle then keeps answering invalid_image, and the call is never charged. Accepted: JPEG, PNG, static WebP; at most 20 MiB and 40 megapixels (16384 px per side) per upload, and a JPEG has at most 64 scans (progressive files from common encoders use about 10; more is 400 invalid_request); a JSON request body is at most 28 MiB so a base64 image fits.

Caching and the SAM encoding fee. SAM-family models (sam3, sam-lite) charge an image encoding fee (encode_image) per call. When the encoding of the same image was already computed for the calling account and is still cached on the GPU node, the fee is waived and the response says "cache": "hit" with "imageFee": 0. This is a bonus, not a promise: cached encodings are deleted after at most 7 days and evicted earlier under capacity pressure, with no minimum retention. Caches are per account and never shared across accounts.

Segmentation results. Instances carry a simplified polygon with holes by default and no mask; masks (COCO compressed RLE or lossless WebP crops) are returned on request. Post-processing (score and size filters, cleanup, overlap removal, merging) is free and configured per prompt; see SegmentRequest and SegmentOptions.

CBOR responses. POST /v1/segment, POST /v1/refine, POST /v1/remove-background and the JSON mode of POST /v1/batch/{endpoint} answer in CBOR (RFC 8949, Content-Type: application/cbor) when Accept lists application/cbor; any other Accept gives JSON. The structure and the keys are those of the JSON response. Polygon rings (outer and each entry of holes) are RFC 8746 typed arrays, tag 69 (uint16, little-endian, x and y interleaved, absolute image pixels); binary payloads (data of WebP masks and of background removal) are byte strings instead of base64; integers are CBOR integers and other numbers are floating point. Requests, errors and event streams are always JSON. A replayed response (Idempotency-Key) follows the Accept of the repeated request.

Errors. {"error": {"code", "message", "retryable", "retryAfterMs"}}. 429 and 503 carry a Retry-After header (seconds). Codes are listed on the Error schema.

Idempotency. Send Idempotency-Key: <1..128 printable ASCII> on any POST that spends credits. Within an account, a key is remembered for 24 hours. Repeating a request with the same body returns the original response (status and body, plus header Idempotent-Replayed: true) and does not charge or run again; the same key with a different body is 409 idempotency_conflict; the same key while the first request is still running is 409 request_in_progress. Only final outcomes are stored (2xx and permanent 4xx); a 402, 429 or 5xx frees the key so the same request can be retried under it. A malformed body (400 invalid_request from the structural check) and a model the calling API key may not use (403 model_locked) are answered before the Idempotency-Key is looked up: they are never stored and never replayed, so a key never receives a stored response for a model it is not allowed to call.

Pools and limits. What a key may call and how fast depends on the account tier (see GET /v1/models for what applies to the calling account). Registered accounts use the public pool (a few models, 100 calls per UTC day, 10 per minute, 429 daily_limit_reached beyond); funded accounts also get the free pool (1,000 calls per UTC day included at no charge) and every model is available against balance. The 60 per minute of the free pool only paces the included calls: a call beyond the daily allowance, or one arriving faster than 60 per minute, is billed from the balance at the normal price and has no per-minute limit (the account’s concurrency limit still applies). A call that would be billed for lack of rate, but that the balance cannot cover, answers 429 rate_limited. Out of balance is 402 insufficient_balance.

Batch. POST /v1/batch/{endpoint} runs up to 1,000 single-call bodies (items) of one endpoint (segment, ocr, documents/parse, embeddings, remove-background) under one model, one after another, in one request. Items are scheduled in the batch class (below interactive and sync traffic, fair between accounts). Each item is priced, billed and settled exactly like a single call, as soon as it finishes; the per-minute rate limit takes one token for the whole request. Images in items must be {"id": "img_..."} handles (upload first). Server-Sent Events (Accept: text/event-stream) is the recommended mode: results arrive item by item and progress heartbeats keep the connection alive (up to 600 s). Plain JSON mode waits for all items and is limited to 90 s; it is not recommended beyond a few items. timeoutSec can only shorten the limit. Items not finished at the limit are returned as expired and are not billed. With Idempotency-Key, a repeated batch replays the finished items. Not available on the Playground trial lane.

More. Guides: Quickstart, Errors, Rate limits and pools, Billing. The machine-readable contract is openapi.yaml.

Information

  • OpenAPI version: 3.1.0

API key created in the console, sent as Authorization: Bearer fbs_.... A key is fbs_ followed by 43 base62 characters and a 6-character checksum. A key may carry model:<id> scopes; when it has any, it can only call those models (403 model_locked otherwise). A missing, malformed, expired or revoked key is 401 unauthorized.

Security scheme type: http

Bearer format: API key