Skip to content

Async jobs, polling and callbacks ​

ModeHow it works
SynchronousExisting /v1/images/generations, /v1/videos/generations and /v1/audio/generations wait for results; requests and responses are unchanged
Async pollingSubmit with POST /api/v1/jobs/createTask, then query saved results using GET /api/v1/jobs/recordInfo?taskId=...
Async callbackInclude callBackUrl and callbackSecret when submitting; ModelFold sends a signed success or failure notification. Polling remains available

Initial support covers image, video and audio models using the unified jobs protocol and having a parameter reference. Chat, Suno and other independent protocols are excluded. Unsupported models return HTTP 400 without charging; use their existing synchronous endpoint. Follow each model's parameter reference, placing native parameters inside input for async requests. Synchronous parameters remain at the top level or in params.

Creation and queries require Authorization: Bearer mf-.... Only the creating API Key can query a job, including when another Key belongs to the same account. JSON bodies are limited to 1 MB; creation and queries share a limit of 120 requests per Key per minute.

Submit a job ​

bash
curl https://ai.modelfold.online/api/v1/jobs/createTask \
  -H "Authorization: Bearer $MODELFOLD_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: order-20261028-001' \
  -d '{"model":"seedream/5-pro-text-to-image","input":{"prompt":"a paper boat in the rain","aspect_ratio":"1:1","quality":"basic"}}'
json
{"code":200,"msg":"success","data":{"taskId":"ecf94083-6e5c-4b3c-b0d1-554d38b3dc20","state":"queued","reused":false}}
FieldRequiredDescription
modelYesModelFold model ID
inputYesNative parameter object; missing required fields or invalid types return 400. Documented duration/resolution defaults are explicitly applied before submission and quoting
callBackUrlNoPublic HTTPS destination on port 443, without credentials or fragments. Public IPv4/IPv6 supported; all DNS answers must be public, with private/reserved IPs blocked
callbackSecretWith callbackYour independently generated 32–256 character signing secret. Stored encrypted and never echoed in responses
Idempotency-Key headerRecommended1–200 characters. Same API Key, idempotency key and request reuse one job without another charge; different parameters return 409. Retained while the job record exists

Callback fields and output-count overrides such as n, num_images and num_outputs are forbidden inside input. Each request generates the model's default number of outputs. Known conflicting inputs are rejected locally; additional upstream validation may cause an asynchronous failure.

HTTP 200 acknowledges acceptance and a credit reservation, rather than successful generation. After a timeout, retry using the same idempotency key; do not create a replacement request with a new key.

Poll saved results ​

bash
curl 'https://ai.modelfold.online/api/v1/jobs/recordInfo?taskId=ecf94083-6e5c-4b3c-b0d1-554d38b3dc20' \
  -H "Authorization: Bearer $MODELFOLD_API_KEY"
json
{
  "code":200,"msg":"success",
  "data":{
    "taskId":"ecf94083-6e5c-4b3c-b0d1-554d38b3dc20",
    "model":"seedream/5-pro-text-to-image","state":"success",
    "resultJson":"{\"resultUrls\":[\"https://ai.modelfold.online/uploads/outputs/result.png\"]}",
    "failMsg":null,"usage":{"credits":19,"settled":true},
    "callback":{"state":"none","attempts":0}
  }
}

Credits are illustrative; usage.credits is authoritative. Parse the JSON string resultJson to obtain resultUrls, which are absolute download URLs. Structured detection results are available as downloadable JSON files.

StateMeaning
queuedAccepted, awaiting upstream submission
submittingSubmission in progress
processingUpstream task ID saved; generation, download or settlement pending
uncertainSubmission outcome unknown; waiting for an upstream callback. No automatic recreation or refund. Contact support with taskId if this persists; do not resubmit
successResults saved and billing settled; read resultJson
failConfirmed failure and reservation refunded; read failMsg. usage.credits is 0

Before completion, usage.credits is the reserved amount and settled is false. Afterwards it is the actual ModelFold charge. Poll every 5–10 seconds and stop at success or fail. Queries only read saved data. Async jobs continue reconciliation beyond the synchronous wait timeout; a timeout alone never triggers a refund.

Receive signed callbacks ​

Add these fields to your submission:

json
{"callBackUrl":"https://your-service.example/webhooks/modelfold","callbackSecret":"replace-with-your-own-random-secret-at-least-32-characters"}

The POST body has the following structure:

json
{
  "eventId":"c783846f-7f2e-4736-9fe3-8524a51836b0",
  "event":"task.completed",
  "data":{
    "taskId":"ecf94083-6e5c-4b3c-b0d1-554d38b3dc20",
    "model":"seedream/5-pro-text-to-image","state":"success",
    "resultJson":"{\"resultUrls\":[\"https://ai.modelfold.online/uploads/outputs/result.png\"]}",
    "failMsg":null,"usage":{"credits":19,"settled":true}
  }
}

Failures also use task.completed, with state: "fail", null resultJson and a descriptive failMsg. Notifications are queued only after result persistence and billing settlement.

Headers:

  • X-ModelFold-Event-Id: event ID, matching body.eventId.
  • X-ModelFold-Timestamp: Unix seconds for this delivery attempt.
  • X-ModelFold-Signature: Base64(HMAC-SHA256(callbackSecret, timestamp + "." + eventId + "." + rawRequestBody)).

Verify the original request bytes before JSON parsing, reject timestamps differing by more than five minutes, and deduplicate by event ID. Retries retain the same event ID/body with a fresh timestamp/signature. Use a separate callback secret rather than your API Key.

Node.js verification example, using express.raw to obtain the original bytes:

js
import crypto from 'node:crypto'
const timestamp = req.get('X-ModelFold-Timestamp') || ''
const eventId = req.get('X-ModelFold-Event-Id') || ''
const received = Buffer.from(req.get('X-ModelFold-Signature') || '', 'base64')
const expected = crypto.createHmac('sha256', process.env.MODELFOLD_CALLBACK_SECRET)
  .update(`${timestamp}.${eventId}.`).update(req.body).digest()
const valid = /^\d+$/.test(timestamp) && Math.abs(Date.now()/1000 - Number(timestamp)) <= 300
  && received.length === expected.length && crypto.timingSafeEqual(received, expected)
if (!valid) return res.sendStatus(403)
const event = JSON.parse(req.body.toString('utf8'))
if (event.eventId !== eventId) return res.sendStatus(403)
// Persist and deduplicate by eventId before acknowledging with 2xx; process business logic in the background.

Return any HTTP 2xx within ten seconds. Redirects are not followed. Network failures, timeouts and non-2xx responses trigger up to ten total attempts, using exponential backoff starting at 30 seconds and capped at one hour. Retries persist across restarts. Query callback.state (none, pending, delivered, exhausted) and callback.attempts for delivery status. Notification failures never alter task results or billing; polling remains available.

Errors and reliability ​

Creation/query failures use HTTP status and {"code":400,"msg":"input.prompt is required","data":null}. Authentication retains the existing gateway error structure; rate limits return 429. Common statuses: 400 invalid input, 401 invalid Key, 402 insufficient credits, 404 missing/unowned task, 409 idempotency conflict, 503 unconfigured upstream.

Job creation, credit reservation and ledger insertion share one transaction. Final state, refund/additional charge, results and the customer notification body share another transaction. Upstream callbacks only wake workers; authoritative results are queried upstream. Callback processing and 30-second fallback polling share database mutual exclusion and terminal-state checks, preventing duplicate settlement. Each job uses an independent random upstream callback token; an upstream HMAC signature and timestamp are additionally verified when operations has configured that key. Customers only configure their own callback endpoint.

Existing synchronous APIs and web Playground behavior remain available. See API gateway for synchronous examples.

ModelFold — one API for all the best AI models.