{"openapi":"3.1.0","info":{"title":"Suede AI","version":"1.0.0","description":"AI-powered music, video, and image generation, payable with USDC on Base via the x402 protocol. Suede turns a text prompt into an original song, a short video clip with native audio, or a still image for cover art, thumbnails, and campaign visuals.","guidance":"Suede AI generates full-length songs, music videos, and images from text prompts. All endpoints require x402 payment (USDC on Base). Send a POST with a JSON body containing at minimum a 'prompt' field. For music: /create-music ($0.50). For video: /agent/video ($4.99). For images: /agent/image ($0.15). Include a PAYMENT-SIGNATURE header to authorize — either an x402 payment payload or a Skyfire pay/kya-pay token (both rails are accepted on the same endpoints). A paid call runs ASYNCHRONOUSLY BY DEFAULT — renders take minutes and payment clients time out in seconds — so expect a jobId/songId plus a pollUrl rather than the finished asset, and collect the result from the poll route below. Add ?async=false to force a blocking call instead. Polling never costs a second payment. Music: POST /create-music answers 202; poll GET /api/songs/{songId} until model_version leaves 'pending' ('failed' is terminal), at which point audio_url is the finished MP3 rather than the placeholder image it starts as. Video: POST /agent/video answers 202 with status 'queued'; poll GET /agent/video/{jobId} until status is 'completed' and videoUrl is set, or 'failed'. Images: POST /agent/image answers 202 with status 'queued'; poll GET /agent/image/{jobId} until status is 'completed' and imageUrl is set, or 'failed'. All three now answer 202 on a queued job, so a 2xx that is not 202 means the asset is in the body already.","x-api-versioning":{"scheme":"header","header":"Suede-API-Version","current":"1","supported":["1"],"default":"1","deprecationHeaders":["Deprecation","Sunset","Link"],"minimumNoticeDays":90,"policy":"Every response carries Suede-API-Version. Send the same header to pin a version; a request without it is served the current version, and an unsupported value is refused with HTTP 400 and code 'unsupported_api_version'. Additive changes (new optional fields, new endpoints, new response fields) ship within a version. A breaking change ships as a new version. Before a version or an operation is withdrawn, its responses carry a Deprecation header (RFC 9745) and a Sunset header (RFC 8594) naming the withdrawal date, at least 90 days in advance, with a Link rel=\"deprecation\" to the notice."}},"servers":[{"url":"https://app.suedeai.ai"}],"tags":[{"name":"SuedeLabs","description":"Suede AI music and media generation platform"},{"name":"SUEDEAI","description":"Suede AI platform services"},{"name":"agent-commerce","description":"Agent-commerce related endpoints"},{"name":"x402","description":"x402 payment protocol endpoints"},{"name":"ACP","description":"Acp related endpoints"},{"name":"AgentCash","description":"AgentCash micropayment integration"},{"name":"music","description":"AI music generation — create full-length songs from text prompts"},{"name":"AIMusic","description":"AI-powered music creation and generative audio"},{"name":"MusicAI","description":"Music intelligence and AI composition"},{"name":"GenerateMusic","description":"Generate an original full-length song from prompts"},{"name":"MusicProduction","description":"Professional music production with AI"},{"name":"text to music","description":"Text to music related endpoints"},{"name":"soundtrack","description":"Soundtrack related endpoints"},{"name":"instrumental","description":"Instrumental related endpoints"},{"name":"beat","description":"Beat related endpoints"},{"name":"backing track","description":"Backing track related endpoints"},{"name":"song","description":"Song related endpoints"},{"name":"songs","description":"Songs related endpoints"},{"name":"songwriting","description":"Songwriting related endpoints"},{"name":"music generation","description":"Music generation related endpoints"},{"name":"AI music","description":"Ai music related endpoints"},{"name":"video","description":"AI video generation — create music videos from prompts"},{"name":"AIVideo","description":"Aivideo related endpoints"},{"name":"VideoGeneration","description":"Videogeneration related endpoints"},{"name":"GenerateVideo","description":"Generatevideo related endpoints"},{"name":"text to video","description":"Text to video related endpoints"},{"name":"short form video","description":"Short form video related endpoints"},{"name":"b-roll","description":"B-roll related endpoints"},{"name":"music video","description":"Music video related endpoints"},{"name":"social video","description":"Social video related endpoints"},{"name":"product video","description":"Product video related endpoints"},{"name":"image","description":"Image related endpoints"},{"name":"AIImage","description":"Aiimage related endpoints"},{"name":"ImageGeneration","description":"Imagegeneration related endpoints"},{"name":"GenerateImage","description":"Generateimage related endpoints"},{"name":"text to image","description":"Text to image related endpoints"},{"name":"cover art","description":"Cover art related endpoints"},{"name":"album art","description":"Album art related endpoints"},{"name":"thumbnail","description":"Thumbnail related endpoints"},{"name":"social graphics","description":"Social graphics related endpoints"},{"name":"concept art","description":"Concept art related endpoints"},{"name":"product shot","description":"Product shot related endpoints"},{"name":"illustration","description":"Illustration related endpoints"},{"name":"digital art","description":"Digital art related endpoints"}],"paths":{"/create-music":{"post":{"summary":"AI music generation from a text prompt. Creates a complete original song with vocals, melody, and full arrangement as a finished MP3, not a loop or preview. Describe genre, mood, instrumentation, and tempo, supply your own lyrics, request an instrumental, or pin a style tag. Use for soundtracks under video, release-ready artist tracks, podcast and game themes, and demo sketches. Async: poll songId until model_version leaves 'pending'.","operationId":"create_music","tags":["SuedeLabs","SUEDEAI","agent-commerce","x402","ACP","AgentCash","music","AIMusic","MusicAI","GenerateMusic","MusicProduction","text to music","soundtrack","instrumental","beat","backing track","song","songs","songwriting","music generation","AI music"],"responses":{"200":{"description":"OK — the job ran synchronously and the body is the finished asset. A paid call only reaches this by passing `?async=false`; without it the response is the 202 below.","content":{"application/json":{"schema":{"type":"object","required":["shareUrl"],"properties":{"shareUrl":{"type":"string","format":"uri","description":"Public URL to listen to and download the track."},"title":{"type":"string","description":"Title of the generated track."},"imageUrl":{"type":"string","format":"uri","description":"Cover art image URL."}}}}},"headers":{"Suede-API-Version":{"description":"The API version that served this response. See info.x-api-versioning.","schema":{"type":"string","enum":["1"]}}}},"400":{"description":"Bad Request — e.g. an unsupported Suede-API-Version header (code 'unsupported_api_version').","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"detail":"Unsupported Suede-API-Version '9'. Supported: 1.","code":"unsupported_api_version"}}},"headers":{"Suede-API-Version":{"description":"The API version that served this response. See info.x-api-versioning.","schema":{"type":"string","enum":["1"]}}}},"402":{"description":"Payment Required — x402 challenge. The response body carries the PaymentRequirements payload (network, asset, maxAmountRequired, payTo, etc.). Re-send the same request with a PAYMENT-SIGNATURE header to authorize.","headers":{"Retry-After":{"description":"RFC 7231 retry hint, in seconds. Always set on 429 and may be set on 402 challenges when the facilitator is back-pressured.","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Total request quota for the active window.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Remaining requests in the active window before throttling kicks in.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix timestamp (seconds) at which the rate-limit window resets.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"IETF RateLimit-Policy field (draft-ietf-httpapi-ratelimit-headers): the quota `q` per window `w` seconds, e.g. `\"probe\";q=20;w=60`. Sent on every response the unauthenticated limiter counts.","schema":{"type":"string"}},"RateLimit":{"description":"IETF RateLimit field: requests remaining `r` and seconds `t` until the window frees a slot, e.g. `\"probe\";r=17;t=42`.","schema":{"type":"string"}},"WWW-Authenticate":{"description":"Always 'x402' on a payment challenge.","schema":{"type":"string"}},"Suede-API-Version":{"description":"The API version that served this response. See info.x-api-versioning.","schema":{"type":"string","enum":["1"]}}},"content":{"application/json":{"schema":{"type":"object","required":["x402Version","accepts"],"properties":{"x402Version":{"type":"integer","description":"x402 protocol version."},"accepts":{"type":"array","items":{"type":"object"},"description":"Accepted PaymentRequirements (per Coinbase x402 spec)."},"error":{"type":"string","description":"Optional human-readable hint."}}}}}},"429":{"description":"Too Many Requests — rate-limited. Honor `Retry-After` before retrying.","headers":{"Retry-After":{"description":"RFC 7231 retry hint, in seconds. Always set on 429 and may be set on 402 challenges when the facilitator is back-pressured.","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Total request quota for the active window.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Remaining requests in the active window before throttling kicks in.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix timestamp (seconds) at which the rate-limit window resets.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"IETF RateLimit-Policy field (draft-ietf-httpapi-ratelimit-headers): the quota `q` per window `w` seconds, e.g. `\"probe\";q=20;w=60`. Sent on every response the unauthenticated limiter counts.","schema":{"type":"string"}},"RateLimit":{"description":"IETF RateLimit field: requests remaining `r` and seconds `t` until the window frees a slot, e.g. `\"probe\";r=17;t=42`.","schema":{"type":"string"}},"Suede-API-Version":{"description":"The API version that served this response. See info.x-api-versioning.","schema":{"type":"string","enum":["1"]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"detail":"Too many requests","code":"rate_limited"}}}},"5XX":{"description":"Server or upstream failure. Safe to retry with backoff, reusing the same X-Idempotency-Key; a request that fails with a 5XX is not charged.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Suede-API-Version":{"description":"The API version that served this response. See info.x-api-versioning.","schema":{"type":"string","enum":["1"]}}}},"422":{"description":"Unprocessable Content — the request body failed validation. `detail` lists each issue. Fix the body and retry; a paid request that fails validation is not charged.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"detail":[{"loc":["body","prompt"],"msg":"Field required","type":"missing"}]}}},"headers":{"Suede-API-Version":{"description":"The API version that served this response. See info.x-api-versioning.","schema":{"type":"string","enum":["1"]}}}},"413":{"description":"Music JSON body exceeds the 64 KiB ceiling (or a lower configured upload limit).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Suede-API-Version":{"description":"The API version that served this response. See info.x-api-versioning.","schema":{"type":"string","enum":["1"]}}}},"202":{"description":"Accepted — job queued for asynchronous execution. This is the normal response to a paid call, not an opt-in: async is the default whenever a PAYMENT-SIGNATURE header is present, and `?async=false` is what turns it off. GET the returned `pollUrl` until the job finishes; polling needs no further payment.","content":{"application/json":{"schema":{"type":"object","required":["status","pollUrl"],"properties":{"status":{"type":"string","enum":["processing","queued"],"description":"Job lifecycle state at the time the request was accepted."},"shareUrl":{"type":"string","format":"uri","description":"Predicted browser-friendly share URL once the job completes."},"songId":{"type":["string","null"],"description":"Stable id for the placeholder row, and the {songId} path segment of pollUrl. May be null when the job is queued before placeholder creation."},"pollUrl":{"type":"string","format":"uri","description":"Absolute URL the client should GET to retrieve the finished asset — GET /api/songs/{songId}. Requires no further payment."}},"additionalProperties":true}}},"headers":{"Suede-API-Version":{"description":"The API version that served this response. See info.x-api-versioning.","schema":{"type":"string","enum":["1"]}}}}},"x-payment-info":{"protocols":["x402","skyfire"],"pricingMode":"fixed","price":"0.50"},"security":[{"SkyfireJWT":[]},{"x402Payment":[]}],"x-bazaar":{"tags":["SuedeLabs","SUEDEAI","agent-commerce","x402","ACP","AgentCash","music","AIMusic","MusicAI","GenerateMusic","MusicProduction","text to music","soundtrack","instrumental","beat","backing track","song","songs","songwriting","music generation","AI music"],"category":"music","info":{"input":{"type":"http","method":"POST","bodyType":"json","body":{"type":"object","required":["prompt"],"properties":{"prompt":{"type":"string","maxLength":8192,"description":"Describe the song you want to create. Include genre, mood, instruments, and any specific vibe. Example: 'Upbeat 80s synthwave with driving bass and neon atmosphere' or 'A melancholic acoustic guitar ballad about rain'."},"style":{"type":"string","maxLength":1024,"description":"Specific musical style or genre tag (e.g., 'Hip Hop', 'Ambient', 'Rock'). Helping the AI focus on a specific sound."},"custom_mode":{"type":"boolean","description":"Set to true to use your own lyrics provided in the 'lyrics' field."},"lyrics":{"type":"string","maxLength":16000,"description":"Your custom lyrics. Required if custom_mode is true."},"make_instrumental":{"type":"boolean","description":"If true, generates a track without vocals."},"vocal_gender":{"type":"string","maxLength":32,"enum":["m","f"],"description":"Preferred gender for the vocalist ('m' for male, 'f' for female)."},"tags":{"type":"string","maxLength":1024,"description":"Comma-separated keywords to tag the generated file."}}}},"output":{"type":"json","example":{}}},"schema":{"type":"object","properties":{"input":{"type":"object","properties":{"body":{"type":"object","required":["prompt"],"properties":{"prompt":{"type":"string","maxLength":8192,"description":"Describe the song you want to create. Include genre, mood, instruments, and any specific vibe. Example: 'Upbeat 80s synthwave with driving bass and neon atmosphere' or 'A melancholic acoustic guitar ballad about rain'."},"style":{"type":"string","maxLength":1024,"description":"Specific musical style or genre tag (e.g., 'Hip Hop', 'Ambient', 'Rock'). Helping the AI focus on a specific sound."},"custom_mode":{"type":"boolean","description":"Set to true to use your own lyrics provided in the 'lyrics' field."},"lyrics":{"type":"string","maxLength":16000,"description":"Your custom lyrics. Required if custom_mode is true."},"make_instrumental":{"type":"boolean","description":"If true, generates a track without vocals."},"vocal_gender":{"type":"string","maxLength":32,"enum":["m","f"],"description":"Preferred gender for the vocalist ('m' for male, 'f' for female)."},"tags":{"type":"string","maxLength":1024,"description":"Comma-separated keywords to tag the generated file."}}}}},"output":{"type":"object","properties":{"example":{"type":"object","required":["shareUrl"],"properties":{"shareUrl":{"type":"string","format":"uri","description":"Public URL to listen to and download the track."},"title":{"type":"string","description":"Title of the generated track."},"imageUrl":{"type":"string","format":"uri","description":"Cover art image URL."}}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["prompt"],"properties":{"prompt":{"type":"string","maxLength":8192,"description":"Describe the song you want to create. Include genre, mood, instruments, and any specific vibe. Example: 'Upbeat 80s synthwave with driving bass and neon atmosphere' or 'A melancholic acoustic guitar ballad about rain'."},"style":{"type":"string","maxLength":1024,"description":"Specific musical style or genre tag (e.g., 'Hip Hop', 'Ambient', 'Rock'). Helping the AI focus on a specific sound."},"custom_mode":{"type":"boolean","description":"Set to true to use your own lyrics provided in the 'lyrics' field."},"lyrics":{"type":"string","maxLength":16000,"description":"Your custom lyrics. Required if custom_mode is true."},"make_instrumental":{"type":"boolean","description":"If true, generates a track without vocals."},"vocal_gender":{"type":"string","maxLength":32,"enum":["m","f"],"description":"Preferred gender for the vocalist ('m' for male, 'f' for female)."},"tags":{"type":"string","maxLength":1024,"description":"Comma-separated keywords to tag the generated file."},"asyncMode":{"type":"boolean","default":false,"description":"Request-body equivalent of `?async=true`, read only when the `async` query parameter is absent. It can switch asynchronous execution ON but never off: `false` is indistinguishable from omitting the field, so a request carrying a PAYMENT-SIGNATURE header still queues even with `asyncMode: false`. `?async=false` is the only way to force a blocking call. Useful mainly to an API-key caller, which would otherwise block. Accepted identically on all three paid routes."}}}}}},"parameters":[{"name":"PAYMENT-SIGNATURE","in":"header","required":true,"description":"Signed payment authorization. Accepts either an x402-compatible payment payload (base64 PaymentPayload) or a Skyfire pay or kya-pay JWT. Skyfire tokens are verified against Skyfire's JWKS and charged via the Skyfire charge-token API; x402 payloads settle USDC on Base through the facilitator. Omit on the first call to receive the 402 challenge, then retry with this header to authorize.","schema":{"type":"string"}},{"name":"X-Idempotency-Key","in":"header","required":false,"description":"Client-chosen job key, scoped to the verified payment, owner and body. Payment authorizations are single-use: replaying one may be rejected. After a 202, poll the returned pollUrl. A fresh payment authorization can create and charge for a new job even with the same key.","schema":{"type":"string","maxLength":200}},{"name":"Suede-API-Version","in":"header","required":false,"description":"Pin the API version. Omit to be served the current version. An unsupported value is refused with 400 and code 'unsupported_api_version'.","schema":{"type":"string","enum":["1"],"default":"1"}},{"name":"async","in":"query","required":false,"description":"Explicit override of the execution mode. Asynchronous execution is already the DEFAULT for any request carrying a PAYMENT-SIGNATURE header: x402 and Skyfire clients time out around 30 seconds and a render takes minutes, so a paid call queues the job and answers with a pollUrl. Pass 'false' to force the blocking call anyway; pass 'true' to queue an API-key call, which would otherwise block. Only the literal 'true' selects async: the server trims and lowercases this value and compares it to 'true', so '1', 'yes', and 'on' all read as 'false'. A paid caller that sends one of them gets the blocking call and its payment client times out mid-render. The asynchronous response names the GET that returns the finished asset, and polling it costs nothing extra. Resolution order on this route is: this query parameter, then the request body's `asyncMode`, then the presence of a PAYMENT-SIGNATURE header. Note that `asyncMode` can only switch async ON. `asyncMode: false` is indistinguishable from omitting the field, so it leaves a paid call asynchronous; this query parameter is the only way to force a blocking call.","schema":{"type":"string","enum":["true","false"]}}]}},"/api/songs/{songId}":{"get":{"operationId":"create_music_result","summary":"Retrieve a queued music job by songId","description":"Collect the track from an asynchronous /create-music job, using the songId its 202 Accepted response returned (the last path segment of that response's pollUrl). Requires no further payment — the track was charged when the job was created. Music does not use the jobId/status envelope the video and image polls use: this returns the song row. Poll until model_version leaves 'pending'; 'failed' is terminal, and any version label means audio_url is now the finished MP3.","tags":["SuedeLabs","SUEDEAI","agent-commerce","x402","ACP","AgentCash","music","AIMusic","MusicAI","GenerateMusic","MusicProduction","text to music","soundtrack","instrumental","beat","backing track","song","songs","songwriting","music generation","AI music"],"parameters":[{"name":"songId","in":"path","required":true,"description":"songId from the 202 Accepted response of the paid POST.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The song row. Inspect model_version for the render state.","content":{"application/json":{"schema":{"type":"object","required":["id","audio_url","model_version"],"properties":{"id":{"type":"string","format":"uuid","description":"The songId that was polled."},"share_id":{"type":["string","null"],"format":"uuid","description":"Public share identifier for the listener-facing page."},"title":{"type":["string","null"],"description":"Track title."},"prompt":{"type":["string","null"],"description":"Echo of the prompt the track was generated from."},"audio_url":{"type":"string","format":"uri","description":"The finished MP3 once the track is rendered. Until then it holds the placeholder cover-image URL the row was created with — a reachable image URL, not audio — so its presence alone must not be read as completion. Check model_version."},"image_url":{"type":["string","null"],"format":"uri","description":"Cover art URL."},"duration":{"type":["integer","null"],"description":"Track length in seconds. 0 until the render finishes."},"genre":{"type":["string","null"],"description":"Style/genre label carried from the request."},"model_version":{"type":"string","description":"The job state. 'pending' while the track is queued or rendering, 'failed' if generation failed (terminal — stop polling), and a version label such as 'v4.5' once the track is ready and audio_url is real audio."},"is_public":{"type":["boolean","null"],"description":"True for x402/Skyfire-paid jobs, which are created public so the buyer can fetch them."},"created_at":{"type":["string","null"],"format":"date-time","description":"Row creation timestamp (ISO 8601)."}}}}}},"404":{"description":"Not Found — no readable song for that songId. Paid jobs are created public, so a 404 here means the id is wrong or was never created, not that the track is still rendering.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"5XX":{"description":"Server or upstream failure. Safe to retry with backoff, reusing the same X-Idempotency-Key; a request that fails with a 5XX is not charged.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[],"x-suede-poll-of":"/create-music"}},"/agent/video":{"post":{"summary":"AI video generation from a text prompt. Returns an 8-second 720p clip with native audio. Use for short-form video, b-roll, product shots, music-video visuals, social clips, and ads. Include sound cues (instruments, voices, weather, movement) since audio is generated from the scene; a silent scene renders near-silent by design. Async by default: poll the returned pollUrl for videoUrl, or pass ?async=false to block.","operationId":"agent_video","tags":["SuedeLabs","SUEDEAI","agent-commerce","x402","ACP","AgentCash","video","AIVideo","VideoGeneration","GenerateVideo","text to video","short form video","b-roll","music video","social video","product video"],"responses":{"200":{"description":"OK — the job ran synchronously and the body is the finished asset. A paid call only reaches this by passing `?async=false`; without it the response is the 202 below.","content":{"application/json":{"schema":{"type":"object","required":["jobId","status","provider"],"properties":{"jobId":{"type":"string","description":"Job identifier for the render."},"status":{"type":"string","description":"Current render status: 'queued' or 'processing' while the render runs, then the terminal 'completed' or 'failed'."},"provider":{"type":"string","description":"Provider handling the render."},"videoUrl":{"type":["string","null"],"format":"uri","description":"Generated video URL when the render is complete; null until then."},"pollUrl":{"type":["string","null"],"format":"uri","description":"Absolute URL to GET for the finished render, returned on the async accept. Needs no further payment. Null on a poll response."},"videoId":{"type":["string","null"],"description":"Suede video record identifier when available."},"pageUrl":{"type":["string","null"],"format":"uri","description":"Suede share-page URL when available."}}}}},"headers":{"Suede-API-Version":{"description":"The API version that served this response. See info.x-api-versioning.","schema":{"type":"string","enum":["1"]}}}},"400":{"description":"Bad Request — e.g. an unsupported Suede-API-Version header (code 'unsupported_api_version').","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"detail":"Unsupported Suede-API-Version '9'. Supported: 1.","code":"unsupported_api_version"}}},"headers":{"Suede-API-Version":{"description":"The API version that served this response. See info.x-api-versioning.","schema":{"type":"string","enum":["1"]}}}},"402":{"description":"Payment Required — x402 challenge. The response body carries the PaymentRequirements payload (network, asset, maxAmountRequired, payTo, etc.). Re-send the same request with a PAYMENT-SIGNATURE header to authorize.","headers":{"Retry-After":{"description":"RFC 7231 retry hint, in seconds. Always set on 429 and may be set on 402 challenges when the facilitator is back-pressured.","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Total request quota for the active window.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Remaining requests in the active window before throttling kicks in.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix timestamp (seconds) at which the rate-limit window resets.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"IETF RateLimit-Policy field (draft-ietf-httpapi-ratelimit-headers): the quota `q` per window `w` seconds, e.g. `\"probe\";q=20;w=60`. Sent on every response the unauthenticated limiter counts.","schema":{"type":"string"}},"RateLimit":{"description":"IETF RateLimit field: requests remaining `r` and seconds `t` until the window frees a slot, e.g. `\"probe\";r=17;t=42`.","schema":{"type":"string"}},"WWW-Authenticate":{"description":"Always 'x402' on a payment challenge.","schema":{"type":"string"}},"Suede-API-Version":{"description":"The API version that served this response. See info.x-api-versioning.","schema":{"type":"string","enum":["1"]}}},"content":{"application/json":{"schema":{"type":"object","required":["x402Version","accepts"],"properties":{"x402Version":{"type":"integer","description":"x402 protocol version."},"accepts":{"type":"array","items":{"type":"object"},"description":"Accepted PaymentRequirements (per Coinbase x402 spec)."},"error":{"type":"string","description":"Optional human-readable hint."}}}}}},"429":{"description":"Too Many Requests — rate-limited. Honor `Retry-After` before retrying.","headers":{"Retry-After":{"description":"RFC 7231 retry hint, in seconds. Always set on 429 and may be set on 402 challenges when the facilitator is back-pressured.","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Total request quota for the active window.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Remaining requests in the active window before throttling kicks in.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix timestamp (seconds) at which the rate-limit window resets.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"IETF RateLimit-Policy field (draft-ietf-httpapi-ratelimit-headers): the quota `q` per window `w` seconds, e.g. `\"probe\";q=20;w=60`. Sent on every response the unauthenticated limiter counts.","schema":{"type":"string"}},"RateLimit":{"description":"IETF RateLimit field: requests remaining `r` and seconds `t` until the window frees a slot, e.g. `\"probe\";r=17;t=42`.","schema":{"type":"string"}},"Suede-API-Version":{"description":"The API version that served this response. See info.x-api-versioning.","schema":{"type":"string","enum":["1"]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"detail":"Too many requests","code":"rate_limited"}}}},"5XX":{"description":"Server or upstream failure. Safe to retry with backoff, reusing the same X-Idempotency-Key; a request that fails with a 5XX is not charged.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Suede-API-Version":{"description":"The API version that served this response. See info.x-api-versioning.","schema":{"type":"string","enum":["1"]}}}},"422":{"description":"Unprocessable Content — the request body failed validation. `detail` lists each issue. Fix the body and retry; a paid request that fails validation is not charged.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"detail":[{"loc":["body","prompt"],"msg":"Field required","type":"missing"}]}}},"headers":{"Suede-API-Version":{"description":"The API version that served this response. See info.x-api-versioning.","schema":{"type":"string","enum":["1"]}}}},"202":{"description":"Accepted — job queued for asynchronous execution. This is the normal response to a paid call, not an opt-in: async is the default whenever a PAYMENT-SIGNATURE header is present, and `?async=false` is what turns it off. GET the returned `pollUrl` until the job finishes; polling needs no further payment.","content":{"application/json":{"schema":{"type":"object","required":["status","pollUrl"],"properties":{"status":{"type":"string","enum":["processing","queued"],"description":"Job lifecycle state at the time the request was accepted."},"shareUrl":{"type":"string","format":"uri","description":"Predicted browser-friendly share URL once the job completes."},"songId":{"type":["string","null"],"description":"Stable id for the placeholder row, and the {songId} path segment of pollUrl. May be null when the job is queued before placeholder creation."},"pollUrl":{"type":"string","format":"uri","description":"Absolute URL the client should GET to retrieve the finished asset — GET /api/songs/{songId}. Requires no further payment."}},"additionalProperties":true}}},"headers":{"Suede-API-Version":{"description":"The API version that served this response. See info.x-api-versioning.","schema":{"type":"string","enum":["1"]}}}}},"x-payment-info":{"protocols":["x402","skyfire"],"pricingMode":"fixed","price":"4.99"},"security":[{"SkyfireJWT":[]},{"x402Payment":[]}],"x-bazaar":{"tags":["SuedeLabs","SUEDEAI","agent-commerce","x402","ACP","AgentCash","video","AIVideo","VideoGeneration","GenerateVideo","text to video","short form video","b-roll","music video","social video","product video"],"category":"video","info":{"input":{"type":"http","method":"POST","bodyType":"json","body":{"type":"object","required":["prompt"],"properties":{"prompt":{"type":"string","description":"Narrative or visual prompt to drive the video concept."},"durationSeconds":{"type":"integer","description":"Requested clip length in seconds; the service maps it to a supported render length.","default":8,"minimum":3,"maximum":15},"aspectRatio":{"type":"string","enum":["16:9","9:16","1:1"],"description":"Desired frame aspect ratio."}}}},"output":{"type":"json","example":{}}},"schema":{"type":"object","properties":{"input":{"type":"object","properties":{"body":{"type":"object","required":["prompt"],"properties":{"prompt":{"type":"string","description":"Narrative or visual prompt to drive the video concept."},"durationSeconds":{"type":"integer","description":"Requested clip length in seconds; the service maps it to a supported render length.","default":8,"minimum":3,"maximum":15},"aspectRatio":{"type":"string","enum":["16:9","9:16","1:1"],"description":"Desired frame aspect ratio."}}}}},"output":{"type":"object","properties":{"example":{"type":"object","required":["jobId","status","provider"],"properties":{"jobId":{"type":"string","description":"Job identifier for the render."},"status":{"type":"string","description":"Current render status: 'queued' or 'processing' while the render runs, then the terminal 'completed' or 'failed'."},"provider":{"type":"string","description":"Provider handling the render."},"videoUrl":{"type":["string","null"],"format":"uri","description":"Generated video URL when the render is complete; null until then."},"pollUrl":{"type":["string","null"],"format":"uri","description":"Absolute URL to GET for the finished render, returned on the async accept. Needs no further payment. Null on a poll response."},"videoId":{"type":["string","null"],"description":"Suede video record identifier when available."},"pageUrl":{"type":["string","null"],"format":"uri","description":"Suede share-page URL when available."}}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["prompt"],"properties":{"prompt":{"type":"string","description":"Narrative or visual prompt to drive the video concept."},"durationSeconds":{"type":"integer","description":"Requested clip length in seconds; the service maps it to a supported render length.","default":8,"minimum":3,"maximum":15},"aspectRatio":{"type":"string","enum":["16:9","9:16","1:1"],"description":"Desired frame aspect ratio."},"asyncMode":{"type":"boolean","default":false,"description":"Request-body equivalent of `?async=true`, read only when the `async` query parameter is absent. It can switch asynchronous execution ON but never off: `false` is indistinguishable from omitting the field, so a request carrying a PAYMENT-SIGNATURE header still queues even with `asyncMode: false`. `?async=false` is the only way to force a blocking call. Useful mainly to an API-key caller, which would otherwise block. Accepted identically on all three paid routes."}}}}}},"parameters":[{"name":"PAYMENT-SIGNATURE","in":"header","required":true,"description":"Signed payment authorization. Accepts either an x402-compatible payment payload (base64 PaymentPayload) or a Skyfire pay or kya-pay JWT. Skyfire tokens are verified against Skyfire's JWKS and charged via the Skyfire charge-token API; x402 payloads settle USDC on Base through the facilitator. Omit on the first call to receive the 402 challenge, then retry with this header to authorize.","schema":{"type":"string"}},{"name":"X-Idempotency-Key","in":"header","required":false,"description":"Client-supplied idempotency token. Re-sending the same key + body within the cache TTL returns the original response without re-charging the payer. Recommended for any POST that triggers a non-idempotent backend job (music/video render, mastering, etc.).","schema":{"type":"string","maxLength":200}},{"name":"Suede-API-Version","in":"header","required":false,"description":"Pin the API version. Omit to be served the current version. An unsupported value is refused with 400 and code 'unsupported_api_version'.","schema":{"type":"string","enum":["1"],"default":"1"}},{"name":"async","in":"query","required":false,"description":"Explicit override of the execution mode. Asynchronous execution is already the DEFAULT for any request carrying a PAYMENT-SIGNATURE header: x402 and Skyfire clients time out around 30 seconds and a render takes minutes, so a paid call queues the job and answers with a pollUrl. Pass 'false' to force the blocking call anyway; pass 'true' to queue an API-key call, which would otherwise block. Only the literal 'true' selects async: the server trims and lowercases this value and compares it to 'true', so '1', 'yes', and 'on' all read as 'false'. A paid caller that sends one of them gets the blocking call and its payment client times out mid-render. The asynchronous response names the GET that returns the finished asset, and polling it costs nothing extra. Resolution order on this route is: this query parameter, then the request body's `asyncMode`, then the presence of a PAYMENT-SIGNATURE header. Note that `asyncMode` can only switch async ON. `asyncMode: false` is indistinguishable from omitting the field, so it leaves a paid call asynchronous; this query parameter is the only way to force a blocking call.","schema":{"type":"string","enum":["true","false"]}}]}},"/agent/video/{jobId}":{"get":{"operationId":"agent_video_status","summary":"Retrieve a queued video job by jobId","description":"Collect the video from an asynchronous /agent/video job, using the jobId that response returned (the last path segment of its pollUrl). Requires no further payment — the job was charged when it was created. Returns the same body shape as /agent/video itself, so one response schema covers both the blocking and the polled path. Poll until status is 'completed' (with videoUrl set) or 'failed'; both are terminal, 'processing' means keep polling. An unknown or expired jobId answers 200 with status 'failed', not 404.","tags":["SuedeLabs","SUEDEAI","agent-commerce","x402","ACP","AgentCash","video","AIVideo","VideoGeneration","GenerateVideo","text to video","short form video","b-roll","music video","social video","product video"],"parameters":[{"name":"jobId","in":"path","required":true,"description":"jobId from the asynchronous response of the paid POST.","schema":{"type":"string"}},{"name":"Suede-API-Version","in":"header","required":false,"description":"Pin the API version. Omit to be served the current version. An unsupported value is refused with 400 and code 'unsupported_api_version'.","schema":{"type":"string","enum":["1"],"default":"1"}}],"responses":{"200":{"description":"Current job state. Every field other than jobId, status and provider is null until the render completes.","content":{"application/json":{"schema":{"type":"object","required":["jobId","status","provider"],"properties":{"jobId":{"type":"string","description":"Job identifier for the render."},"status":{"type":"string","description":"Current render status: 'queued' or 'processing' while the render runs, then the terminal 'completed' or 'failed'."},"provider":{"type":"string","description":"Provider handling the render."},"videoUrl":{"type":["string","null"],"format":"uri","description":"Generated video URL when the render is complete; null until then."},"pollUrl":{"type":["string","null"],"format":"uri","description":"Absolute URL to GET for the finished render, returned on the async accept. Needs no further payment. Null on a poll response."},"videoId":{"type":["string","null"],"description":"Suede video record identifier when available."},"pageUrl":{"type":["string","null"],"format":"uri","description":"Suede share-page URL when available."}}}}},"headers":{"Suede-API-Version":{"description":"The API version that served this response. See info.x-api-versioning.","schema":{"type":"string","enum":["1"]}}}},"400":{"description":"Bad Request — e.g. an unsupported Suede-API-Version header (code 'unsupported_api_version').","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"detail":"Unsupported Suede-API-Version '9'. Supported: 1.","code":"unsupported_api_version"}}},"headers":{"Suede-API-Version":{"description":"The API version that served this response. See info.x-api-versioning.","schema":{"type":"string","enum":["1"]}}}},"5XX":{"description":"Server or upstream failure. Safe to retry with backoff, reusing the same X-Idempotency-Key; a request that fails with a 5XX is not charged.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Suede-API-Version":{"description":"The API version that served this response. See info.x-api-versioning.","schema":{"type":"string","enum":["1"]}}}}},"security":[],"x-suede-poll-of":"/agent/video"}},"/agent/image":{"post":{"summary":"AI image generation from a text prompt. Generate album and single cover art, podcast and video thumbnails, social and campaign graphics, concept art, storyboard frames, product shots, and article illustrations. Returns one hosted still image as PNG or JPEG in square, portrait, or widescreen framing (1:1, 4:5, 9:16, 16:9, 21:9). Async by default: poll the returned pollUrl for imageUrl, or pass ?async=false to block.","operationId":"agent_image","tags":["SuedeLabs","SUEDEAI","agent-commerce","x402","ACP","AgentCash","image","AIImage","ImageGeneration","GenerateImage","text to image","cover art","album art","thumbnail","social graphics","concept art","product shot","illustration","digital art"],"responses":{"200":{"description":"OK — the job ran synchronously and the body is the finished asset. A paid call only reaches this by passing `?async=false`; without it the response is the 202 below.","content":{"application/json":{"schema":{"type":"object","required":["jobId","status","provider"],"properties":{"jobId":{"type":"string","description":"Job identifier for the render."},"status":{"type":"string","description":"Current render status: 'queued' or 'processing' while the render runs, then the terminal 'completed' or 'failed'."},"provider":{"type":"string","description":"Provider handling the render."},"imageUrl":{"type":["string","null"],"format":"uri","description":"Generated image URL when the render is complete; null until then."},"pollUrl":{"type":["string","null"],"format":"uri","description":"Absolute URL to GET for the finished render, returned on the async accept. Needs no further payment. Null on a poll response."}}}}},"headers":{"Suede-API-Version":{"description":"The API version that served this response. See info.x-api-versioning.","schema":{"type":"string","enum":["1"]}}}},"400":{"description":"Bad Request — e.g. an unsupported Suede-API-Version header (code 'unsupported_api_version').","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"detail":"Unsupported Suede-API-Version '9'. Supported: 1.","code":"unsupported_api_version"}}},"headers":{"Suede-API-Version":{"description":"The API version that served this response. See info.x-api-versioning.","schema":{"type":"string","enum":["1"]}}}},"402":{"description":"Payment Required — x402 challenge. The response body carries the PaymentRequirements payload (network, asset, maxAmountRequired, payTo, etc.). Re-send the same request with a PAYMENT-SIGNATURE header to authorize.","headers":{"Retry-After":{"description":"RFC 7231 retry hint, in seconds. Always set on 429 and may be set on 402 challenges when the facilitator is back-pressured.","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Total request quota for the active window.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Remaining requests in the active window before throttling kicks in.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix timestamp (seconds) at which the rate-limit window resets.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"IETF RateLimit-Policy field (draft-ietf-httpapi-ratelimit-headers): the quota `q` per window `w` seconds, e.g. `\"probe\";q=20;w=60`. Sent on every response the unauthenticated limiter counts.","schema":{"type":"string"}},"RateLimit":{"description":"IETF RateLimit field: requests remaining `r` and seconds `t` until the window frees a slot, e.g. `\"probe\";r=17;t=42`.","schema":{"type":"string"}},"WWW-Authenticate":{"description":"Always 'x402' on a payment challenge.","schema":{"type":"string"}},"Suede-API-Version":{"description":"The API version that served this response. See info.x-api-versioning.","schema":{"type":"string","enum":["1"]}}},"content":{"application/json":{"schema":{"type":"object","required":["x402Version","accepts"],"properties":{"x402Version":{"type":"integer","description":"x402 protocol version."},"accepts":{"type":"array","items":{"type":"object"},"description":"Accepted PaymentRequirements (per Coinbase x402 spec)."},"error":{"type":"string","description":"Optional human-readable hint."}}}}}},"429":{"description":"Too Many Requests — rate-limited. Honor `Retry-After` before retrying.","headers":{"Retry-After":{"description":"RFC 7231 retry hint, in seconds. Always set on 429 and may be set on 402 challenges when the facilitator is back-pressured.","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Total request quota for the active window.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Remaining requests in the active window before throttling kicks in.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix timestamp (seconds) at which the rate-limit window resets.","schema":{"type":"integer"}},"RateLimit-Policy":{"description":"IETF RateLimit-Policy field (draft-ietf-httpapi-ratelimit-headers): the quota `q` per window `w` seconds, e.g. `\"probe\";q=20;w=60`. Sent on every response the unauthenticated limiter counts.","schema":{"type":"string"}},"RateLimit":{"description":"IETF RateLimit field: requests remaining `r` and seconds `t` until the window frees a slot, e.g. `\"probe\";r=17;t=42`.","schema":{"type":"string"}},"Suede-API-Version":{"description":"The API version that served this response. See info.x-api-versioning.","schema":{"type":"string","enum":["1"]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"detail":"Too many requests","code":"rate_limited"}}}},"5XX":{"description":"Server or upstream failure. Safe to retry with backoff, reusing the same X-Idempotency-Key; a request that fails with a 5XX is not charged.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Suede-API-Version":{"description":"The API version that served this response. See info.x-api-versioning.","schema":{"type":"string","enum":["1"]}}}},"422":{"description":"Unprocessable Content — the request body failed validation. `detail` lists each issue. Fix the body and retry; a paid request that fails validation is not charged.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"detail":[{"loc":["body","prompt"],"msg":"Field required","type":"missing"}]}}},"headers":{"Suede-API-Version":{"description":"The API version that served this response. See info.x-api-versioning.","schema":{"type":"string","enum":["1"]}}}},"202":{"description":"Accepted — job queued for asynchronous execution. This is the normal response to a paid call, not an opt-in: async is the default whenever a PAYMENT-SIGNATURE header is present, and `?async=false` is what turns it off. GET the returned `pollUrl` until the job finishes; polling needs no further payment.","content":{"application/json":{"schema":{"type":"object","required":["status","pollUrl"],"properties":{"status":{"type":"string","enum":["processing","queued"],"description":"Job lifecycle state at the time the request was accepted."},"shareUrl":{"type":"string","format":"uri","description":"Predicted browser-friendly share URL once the job completes."},"songId":{"type":["string","null"],"description":"Stable id for the placeholder row, and the {songId} path segment of pollUrl. May be null when the job is queued before placeholder creation."},"pollUrl":{"type":"string","format":"uri","description":"Absolute URL the client should GET to retrieve the finished asset — GET /api/songs/{songId}. Requires no further payment."}},"additionalProperties":true}}},"headers":{"Suede-API-Version":{"description":"The API version that served this response. See info.x-api-versioning.","schema":{"type":"string","enum":["1"]}}}}},"x-payment-info":{"protocols":["x402","skyfire"],"pricingMode":"fixed","price":"0.15"},"security":[{"SkyfireJWT":[]},{"x402Payment":[]}],"x-bazaar":{"tags":["SuedeLabs","SUEDEAI","agent-commerce","x402","ACP","AgentCash","image","AIImage","ImageGeneration","GenerateImage","text to image","cover art","album art","thumbnail","social graphics","concept art","product shot","illustration","digital art"],"category":"image","info":{"input":{"type":"http","method":"POST","bodyType":"json","body":{"type":"object","required":["prompt"],"properties":{"prompt":{"type":"string","description":"Visual prompt describing the image to generate."},"aspectRatio":{"type":"string","enum":["1:1","9:16","16:9","3:4","4:3","3:2","2:3","5:4","4:5","21:9"],"description":"Desired frame aspect ratio."},"outputFormat":{"type":"string","enum":["png","jpeg"],"description":"Output image format."}}}},"output":{"type":"json","example":{}}},"schema":{"type":"object","properties":{"input":{"type":"object","properties":{"body":{"type":"object","required":["prompt"],"properties":{"prompt":{"type":"string","description":"Visual prompt describing the image to generate."},"aspectRatio":{"type":"string","enum":["1:1","9:16","16:9","3:4","4:3","3:2","2:3","5:4","4:5","21:9"],"description":"Desired frame aspect ratio."},"outputFormat":{"type":"string","enum":["png","jpeg"],"description":"Output image format."}}}}},"output":{"type":"object","properties":{"example":{"type":"object","required":["jobId","status","provider"],"properties":{"jobId":{"type":"string","description":"Job identifier for the render."},"status":{"type":"string","description":"Current render status: 'queued' or 'processing' while the render runs, then the terminal 'completed' or 'failed'."},"provider":{"type":"string","description":"Provider handling the render."},"imageUrl":{"type":["string","null"],"format":"uri","description":"Generated image URL when the render is complete; null until then."},"pollUrl":{"type":["string","null"],"format":"uri","description":"Absolute URL to GET for the finished render, returned on the async accept. Needs no further payment. Null on a poll response."}}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["prompt"],"properties":{"prompt":{"type":"string","description":"Visual prompt describing the image to generate."},"aspectRatio":{"type":"string","enum":["1:1","9:16","16:9","3:4","4:3","3:2","2:3","5:4","4:5","21:9"],"description":"Desired frame aspect ratio."},"outputFormat":{"type":"string","enum":["png","jpeg"],"description":"Output image format."},"asyncMode":{"type":"boolean","default":false,"description":"Request-body equivalent of `?async=true`, read only when the `async` query parameter is absent. It can switch asynchronous execution ON but never off: `false` is indistinguishable from omitting the field, so a request carrying a PAYMENT-SIGNATURE header still queues even with `asyncMode: false`. `?async=false` is the only way to force a blocking call. Useful mainly to an API-key caller, which would otherwise block. Accepted identically on all three paid routes."}}}}}},"parameters":[{"name":"PAYMENT-SIGNATURE","in":"header","required":true,"description":"Signed payment authorization. Accepts either an x402-compatible payment payload (base64 PaymentPayload) or a Skyfire pay or kya-pay JWT. Skyfire tokens are verified against Skyfire's JWKS and charged via the Skyfire charge-token API; x402 payloads settle USDC on Base through the facilitator. Omit on the first call to receive the 402 challenge, then retry with this header to authorize.","schema":{"type":"string"}},{"name":"X-Idempotency-Key","in":"header","required":false,"description":"Client-supplied idempotency token. Re-sending the same key + body within the cache TTL returns the original response without re-charging the payer. Recommended for any POST that triggers a non-idempotent backend job (music/video render, mastering, etc.).","schema":{"type":"string","maxLength":200}},{"name":"Suede-API-Version","in":"header","required":false,"description":"Pin the API version. Omit to be served the current version. An unsupported value is refused with 400 and code 'unsupported_api_version'.","schema":{"type":"string","enum":["1"],"default":"1"}},{"name":"async","in":"query","required":false,"description":"Explicit override of the execution mode. Asynchronous execution is already the DEFAULT for any request carrying a PAYMENT-SIGNATURE header: x402 and Skyfire clients time out around 30 seconds and a render takes minutes, so a paid call queues the job and answers with a pollUrl. Pass 'false' to force the blocking call anyway; pass 'true' to queue an API-key call, which would otherwise block. Only the literal 'true' selects async: the server trims and lowercases this value and compares it to 'true', so '1', 'yes', and 'on' all read as 'false'. A paid caller that sends one of them gets the blocking call and its payment client times out mid-render. The asynchronous response names the GET that returns the finished asset, and polling it costs nothing extra. Resolution order on this route is: this query parameter, then the request body's `asyncMode`, then the presence of a PAYMENT-SIGNATURE header. Note that `asyncMode` can only switch async ON. `asyncMode: false` is indistinguishable from omitting the field, so it leaves a paid call asynchronous; this query parameter is the only way to force a blocking call.","schema":{"type":"string","enum":["true","false"]}}]}},"/agent/image/{jobId}":{"get":{"operationId":"agent_image_status","summary":"Retrieve a queued image job by jobId","description":"Collect the image from an asynchronous /agent/image job, using the jobId that response returned (the last path segment of its pollUrl). Requires no further payment — the job was charged when it was created. Returns the same body shape as /agent/image itself, so one response schema covers both the blocking and the polled path. Poll until status is 'completed' (with imageUrl set) or 'failed'; both are terminal, 'processing' means keep polling. An unknown or expired jobId answers 200 with status 'failed', not 404.","tags":["SuedeLabs","SUEDEAI","agent-commerce","x402","ACP","AgentCash","image","AIImage","ImageGeneration","GenerateImage","text to image","cover art","album art","thumbnail","social graphics","concept art","product shot","illustration","digital art"],"parameters":[{"name":"jobId","in":"path","required":true,"description":"jobId from the asynchronous response of the paid POST.","schema":{"type":"string"}},{"name":"Suede-API-Version","in":"header","required":false,"description":"Pin the API version. Omit to be served the current version. An unsupported value is refused with 400 and code 'unsupported_api_version'.","schema":{"type":"string","enum":["1"],"default":"1"}}],"responses":{"200":{"description":"Current job state. Every field other than jobId, status and provider is null until the render completes.","content":{"application/json":{"schema":{"type":"object","required":["jobId","status","provider"],"properties":{"jobId":{"type":"string","description":"Job identifier for the render."},"status":{"type":"string","description":"Current render status: 'queued' or 'processing' while the render runs, then the terminal 'completed' or 'failed'."},"provider":{"type":"string","description":"Provider handling the render."},"imageUrl":{"type":["string","null"],"format":"uri","description":"Generated image URL when the render is complete; null until then."},"pollUrl":{"type":["string","null"],"format":"uri","description":"Absolute URL to GET for the finished render, returned on the async accept. Needs no further payment. Null on a poll response."}}}}},"headers":{"Suede-API-Version":{"description":"The API version that served this response. See info.x-api-versioning.","schema":{"type":"string","enum":["1"]}}}},"400":{"description":"Bad Request — e.g. an unsupported Suede-API-Version header (code 'unsupported_api_version').","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"detail":"Unsupported Suede-API-Version '9'. Supported: 1.","code":"unsupported_api_version"}}},"headers":{"Suede-API-Version":{"description":"The API version that served this response. See info.x-api-versioning.","schema":{"type":"string","enum":["1"]}}}},"5XX":{"description":"Server or upstream failure. Safe to retry with backoff, reusing the same X-Idempotency-Key; a request that fails with a 5XX is not charged.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Suede-API-Version":{"description":"The API version that served this response. See info.x-api-versioning.","schema":{"type":"string","enum":["1"]}}}}},"security":[],"x-suede-poll-of":"/agent/image"}}},"components":{"schemas":{"Error":{"type":"object","required":["detail"],"properties":{"detail":{"description":"Human-readable error message; for a 422 the list of validation issues instead.","oneOf":[{"type":"string"},{"type":"array","items":{"$ref":"#/components/schemas/ValidationIssue"}}]},"code":{"type":"string","description":"Machine-readable error code, present where a client should branch on the failure: 'rate_limited' (429), 'unsupported_api_version' (400).","examples":["rate_limited","unsupported_api_version"]}}},"ValidationIssue":{"type":"object","required":["loc","msg","type"],"properties":{"loc":{"type":"array","items":{"oneOf":[{"type":"string"},{"type":"integer"}]},"description":"Path to the offending field, e.g. ['body', 'prompt']."},"msg":{"type":"string","description":"What is wrong with the field."},"type":{"type":"string","description":"Machine-readable validation error type."}}}},"securitySchemes":{"SkyfireJWT":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Skyfire pay+jwt or kya-pay+jwt token issued by Skyfire and verified against https://app.skyfire.xyz/.well-known/jwks.json. Pass in the PAYMENT-SIGNATURE header.","x-header-name":"PAYMENT-SIGNATURE","x-jwks-uri":"https://app.skyfire.xyz/.well-known/jwks.json"},"x402Payment":{"type":"http","scheme":"bearer","bearerFormat":"x402","description":"x402 USDC payment on Base mainnet (eip155:8453). Pass a signed ERC-3009 transferWithAuthorization payload in the PAYMENT-SIGNATURE header.","x-header-name":"PAYMENT-SIGNATURE","x-facilitator":"https://x402.org/facilitator"}}}}