{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["tabs","tab"]},"type":"markdown"},"seo":{"title":"Async requests, webhooks and polling","description":"Generate and edit images and video with Bria's FIBO models through a REST API, Python SDK, MCP server and agent skills. Licensed training data, controllable output, provenance on every result.","siteUrl":"https://docs.bria.ai","image":"/assets/logo.4aab4827f8ef484ab0149a267109951af9b35a6e5d7ddacfc52a0cb2bf07aec6.db81178d.png","llmstxt":{"hide":false,"title":"Bria API documentation","description":"Bria's developer platform: controllable, commercially safe visual generative AI (images and video) as a REST API, Python SDK, MCP server and agent skills.","details":{"path":"_llmstxt-details.md"},"sections":[{"title":"Getting started","description":"First call, authentication, async jobs and webhooks, rate limits, inputs.","includeFiles":["index.md","getting-started/quickstart.md","getting-started/authentication.md","getting-started/async-requests.md","status.yaml","getting-started/rate-limits-and-errors.md","getting-started/working-with-images.md"]},{"title":"Integrate","description":"Python SDK, MCP server, agent skills, and machine-readable docs for agents.","includeFiles":["integration-methods/python-sdk.md","MCP-authentication.md","integration-methods/bria-skill.md","integration-methods/for-ai-agents.md"]},{"title":"Concepts","description":"Platform map, VGL and the FIBO models, safety, best practices.","includeFiles":["products-overview.md","VGL.md","safety.md","best-practices-overview.md","image-generation-best-practices.md","image-editing-best-practices.md","product-shots-best-practices.md"]},{"title":"Image Generation","description":"Generate images from text, reference images or structured (VGL) prompts with FIBO.","includeFiles":["image-generation-overview.md","image-generation.yaml"]},{"title":"Image Editing","description":"Instruction-based editing plus specialized endpoints for backgrounds, erasing, fill, expansion, upscaling and style.","includeFiles":["image-editing-overview.md","image-editing.yaml"]},{"title":"Product Shot Editing","description":"Cutouts, packshots, shadows, lifestyle scenes, product integration, holding, virtual try-on, automotive.","includeFiles":["product-shot-overview.md","product-shot-editing.yaml"]},{"title":"Video Editing","description":"Background removal (REST or real-time streaming), erasing, upscaling and masks for video; local video upload.","includeFiles":["video-editing-overview.md","local-video-upload-service.md","streaming-rmbg.md","video-editing.yaml"]},{"title":"Ad Delayer","description":"Turn a flat ad into editable layers; the guide holds the layer document contract.","includeFiles":["ad-delayer-overview.md","ad-delayer.yaml"]},{"title":"Trust and provenance","description":"Public verification of Bria provenance, and attribution of outputs to licensed training data.","includeFiles":["trust-and-provenance-overview.md","visual-verification-overview.md","visual-verification.yaml","enterprise/attribution.md","bria-attribution-service.yaml"]},{"title":"Enterprise","description":"Run Bria in your own cloud or on-premises.","includeFiles":["enterprise/deployment-options.md"]}],"excludeFiles":["_llmstxt-details.md","README.md"]}},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"async-requests-webhooks-and-polling","__idx":0},"children":["Async requests, webhooks and polling"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["All Bria v2 endpoints process requests asynchronously by default. This keeps long generations from tying up connections and lets you fan out hundreds of jobs at once. Every request follows the same lifecycle:"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Submit."]}," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST"]}," the request. The API validates it and responds with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["202 Accepted"]},", a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["request_id"]}," and a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["status_url"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Receive the result."]}," Either pass a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["webhook_url"]}," and Bria POSTs the result to you when the job finishes (recommended for production), or poll the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["status_url"]}," until it does."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Collect."]}," When ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["status"]}," is ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["COMPLETED"]},", the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["result"]}," object holds the output: ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["image_url"]}," for images, ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["video_url"]}," for videos, ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["structured_prompt"]}," for structured prompt generation, plus endpoint-specific fields such as ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["seed"]},"."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Webhook deliveries and status polls carry the same body, so one parser handles both:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"request_id\": \"9d4a1a2f5c7e4b6f8a0c2d3e4f5a6b7c\",\n  \"status\": \"COMPLETED\",\n  \"result\": {\n    \"image_url\": \"https://.../result.png\",\n    \"seed\": 314159\n  }\n}\n","lang":"json"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"webhooks","__idx":1},"children":["Webhooks"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Pass ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["webhook_url"]}," with any asynchronous request. Use webhooks for pipelines, queues and serverless backends: no polling loops, no open connections, and results arrive the moment a job finishes."]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"TabItemFragment","attributes":{"label":"Python SDK","disable":false},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["webhook_url"]}," is a keyword argument of ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":[".submit()"]},", not part of the payload."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"python","header":{"controls":{"copy":{}}},"source":"from bria_client import BriaSyncClient\n\nclient = BriaSyncClient()  # reads BRIA_API_TOKEN\n\njob = client.submit(\n    endpoint=\"image/generate\",\n    payload={\"prompt\": \"a serene mountain landscape at dawn\"},\n    webhook_url=\"https://your-app.com/api/bria/webhook\",\n)\nprint(\"submitted\", job.request_id)  # the result will be POSTed to your webhook\n","lang":"python"},"children":[]}]},{"$$mdtype":"Tag","name":"TabItemFragment","attributes":{"label":"JavaScript / TypeScript","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"javascript","header":{"controls":{"copy":{}}},"source":"const response = await fetch(\"https://engine.prod.bria-api.com/v2/image/generate\", {\n  method: \"POST\",\n  headers: { api_token: process.env.BRIA_API_TOKEN ?? \"\", \"Content-Type\": \"application/json\" },\n  body: JSON.stringify({\n    prompt: \"a serene mountain landscape at dawn\",\n    webhook_url: \"https://your-app.com/api/bria/webhook\",\n  }),\n});\nconst { request_id } = await response.json();\nconsole.log(\"submitted\", request_id); // the result will be POSTed to your webhook\n","lang":"javascript"},"children":[]}]},{"$$mdtype":"Tag","name":"TabItemFragment","attributes":{"label":"cURL","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"bash","header":{"controls":{"copy":{}}},"source":"curl -X POST https://engine.prod.bria-api.com/v2/image/generate \\\n  -H \"api_token: $BRIA_API_TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"prompt\": \"a serene mountain landscape at dawn\", \"webhook_url\": \"https://your-app.com/api/bria/webhook\"}'\n","lang":"bash"},"children":[]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"what-bria-sends","__idx":2},"children":["What Bria sends"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["When the job reaches a terminal state, Bria sends a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST"]}," with the body shown above and three signed headers:"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Header"},"children":["Header"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Value"},"children":["Value"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Bria-Webhook-Id"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The job's ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["request_id"]},". Use it as your deduplication key."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Bria-Webhook-Timestamp"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Unix epoch seconds when the signature was generated."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Bria-Webhook-Signature"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["v1=<base64>"]},", an HMAC-SHA256 signature (see below)."]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Your endpoint must answer with any ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["2xx"]}," within 10 seconds; do heavy work afterwards, in a queue or background task. If the endpoint is unreachable or returns a non-2xx response, Bria retries with exponential backoff, up to 5 attempts over 45 minutes. Because retries and rare duplicates are possible, treat deliveries as idempotent and key them on ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Bria-Webhook-Id"]},"."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"verify-the-signature","__idx":3},"children":["Verify the signature"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The signing key is derived from your API token (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["HMAC-SHA256(api_token, \"bria-webhook-signing-v1\")"]},"), and the signed message is ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["{webhook_id}.{timestamp}.{raw_body}"]},". Verify with a constant-time comparison before trusting a delivery."]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"TabItemFragment","attributes":{"label":"Python SDK","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"python","header":{"controls":{"copy":{}}},"source":"import os\nfrom bria_client.toolkit import verify_webhook_signature\n\ndef is_valid(raw_body: bytes, headers) -> bool:\n    return verify_webhook_signature(\n        payload=raw_body,\n        webhook_id=headers[\"Bria-Webhook-Id\"],\n        timestamp=headers[\"Bria-Webhook-Timestamp\"],\n        signature_header=headers[\"Bria-Webhook-Signature\"],\n        api_token=os.environ[\"BRIA_API_TOKEN\"],\n    )\n","lang":"python"},"children":[]}]},{"$$mdtype":"Tag","name":"TabItemFragment","attributes":{"label":"JavaScript / TypeScript","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"javascript","header":{"controls":{"copy":{}}},"source":"import crypto from \"node:crypto\";\n\nfunction isValid(rawBody, headers, apiToken = process.env.BRIA_API_TOKEN ?? \"\") {\n  const signature = headers[\"bria-webhook-signature\"] ?? \"\";\n  if (!signature.startsWith(\"v1=\")) return false;\n  const signingKey = crypto.createHmac(\"sha256\", apiToken).update(\"bria-webhook-signing-v1\").digest();\n  const message = `${headers[\"bria-webhook-id\"]}.${headers[\"bria-webhook-timestamp\"]}.${rawBody}`;\n  const expected = crypto.createHmac(\"sha256\", signingKey).update(message).digest(\"base64\");\n  const got = Buffer.from(signature.slice(3));\n  const exp = Buffer.from(expected);\n  return got.length === exp.length && crypto.timingSafeEqual(got, exp);\n}\n","lang":"javascript"},"children":[]}]},{"$$mdtype":"Tag","name":"TabItemFragment","attributes":{"label":"Any language","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"text","header":{"controls":{"copy":{}}},"source":"signing_key = HMAC_SHA256(key = api_token, message = \"bria-webhook-signing-v1\")\nexpected    = BASE64(HMAC_SHA256(key = signing_key, message = webhook_id + \".\" + timestamp + \".\" + raw_body))\nvalid       = constant_time_equal(expected, signature_header without the \"v1=\" prefix)\n","lang":"text"},"children":[]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"a-complete-receiver","__idx":4},"children":["A complete receiver"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Verify, acknowledge, then process in the background."]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"TabItemFragment","attributes":{"label":"Python (FastAPI)","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"python","header":{"controls":{"copy":{}}},"source":"import json\nimport os\n\nfrom bria_client.toolkit import verify_webhook_signature\nfrom fastapi import BackgroundTasks, FastAPI, Header, HTTPException, Request\n\napp = FastAPI()\n\n\n@app.post(\"/api/bria/webhook\")\nasync def receive(\n    request: Request,\n    background: BackgroundTasks,\n    bria_webhook_id: str = Header(...),\n    bria_webhook_timestamp: str = Header(...),\n    bria_webhook_signature: str = Header(...),\n):\n    body = await request.body()\n    if not verify_webhook_signature(\n        payload=body,\n        webhook_id=bria_webhook_id,\n        timestamp=bria_webhook_timestamp,\n        signature_header=bria_webhook_signature,\n        api_token=os.environ[\"BRIA_API_TOKEN\"],\n    ):\n        raise HTTPException(status_code=401, detail=\"Invalid webhook signature\")\n    background.add_task(process, json.loads(body))\n    return {\"ok\": True}\n\n\nasync def process(data: dict):\n    if data[\"status\"] == \"COMPLETED\":\n        ...  # store data[\"result\"][\"image_url\"], notify, trigger the next step\n    elif data[\"status\"] == \"ERROR\":\n        ...  # log data[\"error\"]\n","lang":"python"},"children":[]}]},{"$$mdtype":"Tag","name":"TabItemFragment","attributes":{"label":"JavaScript (Express)","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"javascript","header":{"controls":{"copy":{}}},"source":"import express from \"express\";\nimport crypto from \"node:crypto\";\n\nconst app = express();\n\nfunction isValid(rawBody, headers, apiToken = process.env.BRIA_API_TOKEN ?? \"\") {\n  const signature = headers[\"bria-webhook-signature\"] ?? \"\";\n  if (!signature.startsWith(\"v1=\")) return false;\n  const signingKey = crypto.createHmac(\"sha256\", apiToken).update(\"bria-webhook-signing-v1\").digest();\n  const message = `${headers[\"bria-webhook-id\"]}.${headers[\"bria-webhook-timestamp\"]}.${rawBody}`;\n  const expected = crypto.createHmac(\"sha256\", signingKey).update(message).digest(\"base64\");\n  const got = Buffer.from(signature.slice(3));\n  const exp = Buffer.from(expected);\n  return got.length === exp.length && crypto.timingSafeEqual(got, exp);\n}\n\napp.post(\"/api/bria/webhook\", express.raw({ type: \"application/json\" }), (req, res) => {\n  if (!isValid(req.body.toString(), req.headers)) return res.sendStatus(401);\n  res.sendStatus(200); // acknowledge first\n\n  const { request_id, status, result, error } = JSON.parse(req.body);\n  if (status === \"COMPLETED\") console.log(`job ${request_id} done`, result.image_url);\n  else if (status === \"ERROR\") console.error(`job ${request_id} failed`, error.message);\n});\n\napp.listen(3000);\n","lang":"javascript"},"children":[]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"polling-the-status-endpoint","__idx":5},"children":["Polling the status endpoint"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If you would rather pull than push, call ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["GET /v2/status/{request_id}"]}," (the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["status_url"]}," from the submit response) until the job reaches a terminal state. The ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/status"},"children":["status endpoint reference"]}," has the full response schema."]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"TabItemFragment","attributes":{"label":"Python SDK","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"python","header":{"controls":{"copy":{}}},"source":"job = client.submit(endpoint=\"image/generate\", payload={\"prompt\": \"a serene mountain landscape at dawn\"})\nresult = client.poll(job, interval=2, timeout=120)  # raises TimeoutError after 120 s\nprint(result.result.image_url)\n\n# client.run(...) does submit and poll in one call\n","lang":"python"},"children":[]}]},{"$$mdtype":"Tag","name":"TabItemFragment","attributes":{"label":"JavaScript / TypeScript","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"javascript","header":{"controls":{"copy":{}}},"source":"const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\nconst headers = { api_token: process.env.BRIA_API_TOKEN ?? \"\" };\n\nlet status;\ndo {\n  await sleep(2000);\n  status = await (await fetch(job.status_url, { headers })).json();\n} while (status.status === \"IN_PROGRESS\");\n\nif (status.status !== \"COMPLETED\") throw new Error(JSON.stringify(status.error ?? status));\nconsole.log(status.result.image_url);\n","lang":"javascript"},"children":[]}]},{"$$mdtype":"Tag","name":"TabItemFragment","attributes":{"label":"cURL","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"bash","header":{"controls":{"copy":{}}},"source":"curl \"https://engine.prod.bria-api.com/v2/status/<request_id>\" -H \"api_token: $BRIA_API_TOKEN\"\n","lang":"bash"},"children":[]}]}]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"status"},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["status"]}]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Meaning"},"children":["Meaning"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"What to do"},"children":["What to do"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["IN_PROGRESS"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Accepted and processing."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Keep polling."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["COMPLETED"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Finished successfully."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Read ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["result"]},"."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["ERROR"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Processing failed; ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error"]}," holds ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["code"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["message"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["details"]},"."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Stop polling. Fix the input if it is a validation or moderation error, otherwise retry the submission."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["UNKNOWN"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Unexpected failure, or an unknown or expired ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["request_id"]},"."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Stop polling. Contact ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"mailto:support@bria.ai"},"children":["support@bria.ai"]}," with the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["request_id"]},"."]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The status endpoint returns HTTP ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["200"]}," for all of these; the job state is in the body. A ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["404"]}," means the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["request_id"]}," does not exist or has expired."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Polling guidance:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Poll every 1 to 2 seconds for image endpoints and every 5 seconds for video, with a timeout that fits the workload (a minute for images, ten minutes or more for long videos)."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Status calls count toward your ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/getting-started/rate-limits-and-errors"},"children":["rate limit"]},", so do not poll in a tight loop."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Submissions are not idempotent: retrying a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST"]}," creates a new job. Retry only when the submission itself failed (network error or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["5xx"]},"), never while a job is ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["IN_PROGRESS"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Download results as soon as they are ready and store them yourself. Result URLs are temporary."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"sync-mode","__idx":6},"children":["Sync mode"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Most endpoints accept ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["\"sync\": true"]},", which holds the connection open and returns the result in the response body with HTTP ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["200"]},". It is convenient for quick experiments and low-volume interactive use. Prefer webhooks or polling for production: sync calls occupy a connection for the whole generation, and some options are async-only, for example ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["resolution: \"4MP\""]}," on ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["/v2/image/generate"]}," or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["placement_type: \"automatic\""]}," on lifestyle shots. Combining an async-only option with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["sync: true"]}," returns ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["422"]},"."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Some product-shot endpoints are synchronous by default and document their own ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["sync"]}," behavior; the endpoint pages in the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/product-shot-editing"},"children":["Product Shot Editing reference"]}," state it."]}]},"headings":[{"value":"Async requests, webhooks and polling","id":"async-requests-webhooks-and-polling","depth":1},{"value":"Webhooks","id":"webhooks","depth":2},{"value":"What Bria sends","id":"what-bria-sends","depth":3},{"value":"Verify the signature","id":"verify-the-signature","depth":3},{"value":"A complete receiver","id":"a-complete-receiver","depth":3},{"value":"Polling the status endpoint","id":"polling-the-status-endpoint","depth":2},{"value":"Sync mode","id":"sync-mode","depth":2}],"frontmatter":{"title":"Async requests, webhooks and polling","description":"How Bria's asynchronous v2 endpoints work, how to receive results by webhook, how to poll the status endpoint, and when sync mode is the better choice.","seo":{"title":"Async requests, webhooks and polling"}},"lastModified":"2026-09-27T11:58:15.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/getting-started/async-requests","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}