{"openapi":"3.1.0","info":{"title":"SmileToAI API","description":"Run SmileToAI tools from your own code. Authenticate with a team API key (`Authorization: Bearer stai_live_...`, created in Settings > API keys; `stai_test_...` outside production). Runs spend the team's Sparks at the same price as the app: estimate first, then start a run, then poll `GET /v1/runs/{id}` or receive a signed webhook. Errors are `{\"error\": {\"code\", \"message\", \"request_id\"}}`; every response has `X-Request-Id`.","version":"1.0.0","x-smiletoai-limits":{"key_prefixes":{"production":"stai_live_","other":"stai_test_"},"key_prefix_length":8,"key_secret_length":32,"max_active_keys_per_team":25,"scopes":["read","run","webhooks"],"default_scopes":["read","run"],"rate_limit_choices_per_minute":[30,60,120,300],"default_rate_limit_per_minute":60,"webhook_events":["run.succeeded","run.failed","run.canceled"],"webhook_test_event":"ping","max_webhook_endpoints_per_team":10,"webhook_retry_delays_seconds":[60,300,1800,7200,43200],"webhook_signing_secret_prefix":"whsec_","webhook_headers":{"signature":"SmileToAI-Signature","event":"SmileToAI-Event","delivery":"SmileToAI-Delivery","user_agent":"SmileToAI-Webhooks/1"}},"x-smiletoai-tools":[{"id":"image_upscale","name":"Upscale image","family":"enhance","output_kind":"image","inputs":[{"name":"image","kind":"image","required":true,"choices":null}]},{"id":"video_transition","name":"Video transition","family":"edit","output_kind":"video","inputs":[{"name":"clips","kind":"video","required":true,"choices":null},{"name":"style","kind":"enum","required":false,"choices":["fade","dissolve","wipe_left","wipe_right"]},{"name":"duration_seconds","kind":"number","required":false,"choices":null}]},{"id":"image_color_grade","name":"Colour grade","family":"edit","output_kind":"image","inputs":[{"name":"image","kind":"image","required":true,"choices":null},{"name":"temperature","kind":"number","required":false,"choices":null},{"name":"contrast","kind":"number","required":false,"choices":null},{"name":"saturation","kind":"number","required":false,"choices":null},{"name":"exposure","kind":"number","required":false,"choices":null},{"name":"grain","kind":"number","required":false,"choices":null},{"name":"preset","kind":"enum","required":false,"choices":["natural","warm_film","cool_matte","bw_16mm","none"]}]},{"id":"video_upscale","name":"Upscale video","family":"enhance","output_kind":"video","inputs":[{"name":"video","kind":"video","required":true,"choices":null},{"name":"target","kind":"enum","required":false,"choices":["1080p","4k"]}]},{"id":"brand_kit_extract","name":"Extract brand kit","family":"analyze","output_kind":"json","inputs":[{"name":"url","kind":"text","required":false,"choices":null},{"name":"files","kind":"image","required":false,"choices":null},{"name":"save","kind":"bool","required":false,"choices":null}]}]},"paths":{"/v1/me":{"get":{"tags":["Account"],"summary":"The team and key behind this request","description":"Check that a key works and see the team, plan, scopes and rate limit it carries, and the Sparks the team can spend.","operationId":"get_me_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1Me"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}}},"402":{"description":"Payment Required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}}},"422":{"description":"Unprocessable Entity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}}}},"x-smiletoai-scope":"read"}},"/v1/tools":{"get":{"tags":["Tools"],"summary":"List the tools this key can run","description":"Tools available over the API, with their input slots and a typical price range. allowed is false when the team's plan does not include a tool.","operationId":"list_tools_tools_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ToolList"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}}},"402":{"description":"Payment Required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}}},"422":{"description":"Unprocessable Entity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}}},"429":{"description":"Rate limited; see Retry-After."}},"x-smiletoai-scope":"read"}},"/v1/tools/{tool_id}/estimate":{"post":{"tags":["Tools"],"summary":"Price a run without starting it","description":"Prices the exact inputs you will send. It starts nothing and spends nothing. Video tools take duration_seconds when the length is not known from a file yet.","operationId":"estimate_tool_tools__tool_id__estimate_post","parameters":[{"name":"tool_id","in":"path","required":true,"schema":{"type":"string","description":"A tool id from GET /v1/tools, such as image_upscale.","title":"Tool Id"},"description":"A tool id from GET /v1/tools, such as image_upscale."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1EstimateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1Estimate"}}}},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Unauthorized"},"402":{"description":"The team does not have enough Sparks for the run's hold."},"403":{"description":"plan_upgrade_required, consent_required or insufficient_scope."},"404":{"description":"Unknown or unavailable tool."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Conflict"},"422":{"description":"Invalid inputs, with one entry per bad slot in error.errors."},"429":{"description":"Rate limited; see Retry-After."}},"x-smiletoai-scope":"read"}},"/v1/tools/{tool_id}/runs":{"post":{"tags":["Tools"],"summary":"Start a run (it spends the team's Sparks)","description":"Holds the estimated Sparks, queues the run and answers 202 with it. Repeating an Idempotency-Key returns the run it already started instead of a new one. Read the run with GET /v1/runs/{run_id}, or receive a webhook when it ends.","operationId":"start_run_tools__tool_id__runs_post","parameters":[{"name":"tool_id","in":"path","required":true,"schema":{"type":"string","description":"A tool id from GET /v1/tools, such as image_upscale.","title":"Tool Id"},"description":"A tool id from GET /v1/tools, such as image_upscale."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"description":"Any string up to 255 characters. Sending the same key again returns the run it already started.","title":"Idempotency-Key"},"description":"Any string up to 255 characters. Sending the same key again returns the run it already started."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1RunRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1Run"}}}},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Unauthorized"},"402":{"description":"The team does not have enough Sparks for the run's hold."},"403":{"description":"plan_upgrade_required, consent_required or insufficient_scope."},"404":{"description":"Unknown or unavailable tool."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Conflict"},"422":{"description":"Invalid inputs, with one entry per bad slot in error.errors."},"429":{"description":"Rate limited; see Retry-After."}},"x-smiletoai-scope":"run"}},"/v1/runs/{run_id}":{"get":{"tags":["Runs"],"summary":"Get a run","description":"Only runs started with this team's API keys. Poll every 2 to 5 seconds until the status is succeeded, failed or canceled.","operationId":"get_run_runs__run_id__get","parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of a run started with one of your team's API keys.","title":"Run Id"},"description":"The id of a run started with one of your team's API keys."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1Run"}}}},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Conflict"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Unprocessable Entity"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Too Many Requests"}},"x-smiletoai-scope":"read"}},"/v1/runs/{run_id}/cancel":{"post":{"tags":["Runs"],"summary":"Cancel a queued or running run","description":"Stops the run and releases its hold, as canceling in the app does.","operationId":"cancel_run_runs__run_id__cancel_post","parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of a run started with one of your team's API keys.","title":"Run Id"},"description":"The id of a run started with one of your team's API keys."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1Run"}}}},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Conflict"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Unprocessable Entity"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Too Many Requests"}},"x-smiletoai-scope":"run"}},"/v1/runs/{run_id}/outputs/{asset_id}/url":{"get":{"tags":["Runs"],"summary":"Get a short-lived download URL for an output","description":"A signed URL for one output of a succeeded run. Download straight away and ask again when it expires. 409 output_not_ready means the file is still being checked.","operationId":"get_output_url_runs__run_id__outputs__asset_id__url_get","parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The id of a run started with one of your team's API keys.","title":"Run Id"},"description":"The id of a run started with one of your team's API keys."},{"name":"asset_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"An asset_id from the run's outputs.","title":"Asset Id"},"description":"An asset_id from the run's outputs."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1OutputUrl"}}}},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Conflict"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Unprocessable Entity"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Too Many Requests"}},"x-smiletoai-scope":"read"}},"/v1/files/upload-url":{"post":{"tags":["Files"],"summary":"Start a file upload","description":"Creates a file and returns one presigned URL per part. PUT each part to its URL, keep each ETag response header, then call POST /v1/files/{file_id}/complete.","operationId":"create_upload_url_files_upload_url_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1FileUploadRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1FileUpload"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}}},"402":{"description":"Payment Required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}}},"422":{"description":"Unprocessable Entity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}}}},"x-smiletoai-scope":"run"}},"/v1/files/{file_id}/complete":{"post":{"tags":["Files"],"summary":"Finish a file upload","description":"Completes the upload with every part's ETag. The file id then works in media inputs.","operationId":"complete_upload_files__file_id__complete_post","parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"The file_id from POST /v1/files/upload-url.","title":"File Id"},"description":"The file_id from POST /v1/files/upload-url."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1FileCompleteRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1File"}}}},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Conflict"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Unprocessable Entity"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Too Many Requests"}},"x-smiletoai-scope":"run"}},"/v1/webhook-endpoints":{"get":{"tags":["Webhooks"],"summary":"List webhook endpoints","description":"The team's endpoints. The key's creator must be a team owner or admin.","operationId":"list_endpoints_webhook_endpoints_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1WebhookEndpointList"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}}},"402":{"description":"Payment Required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}}},"422":{"description":"Unprocessable Entity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}}}},"x-smiletoai-scope":"webhooks"},"post":{"tags":["Webhooks"],"summary":"Add a webhook endpoint","description":"Adds an HTTPS endpoint (up to 10 per team) and returns its signing secret once. It receives the runs that finish from now on; nothing earlier is replayed.","operationId":"create_endpoint_webhook_endpoints_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1WebhookEndpointCreateRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1WebhookEndpointCreated"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}}},"402":{"description":"Payment Required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}}},"403":{"description":"Forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}}},"422":{"description":"Unprocessable Entity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}}},"429":{"description":"Too Many Requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}}}},"x-smiletoai-scope":"webhooks"}},"/v1/webhook-endpoints/{endpoint_id}":{"patch":{"tags":["Webhooks"],"summary":"Pause, resume or change events","description":"Pausing drops the endpoint's pending deliveries. A resumed endpoint receives the runs that finish after it is resumed; runs that finished while it was paused are not sent.","operationId":"update_endpoint_webhook_endpoints__endpoint_id__patch","parameters":[{"name":"endpoint_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"A webhook endpoint id.","title":"Endpoint Id"},"description":"A webhook endpoint id."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1WebhookEndpointUpdateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1WebhookEndpoint"}}}},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Conflict"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Unprocessable Entity"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Too Many Requests"}},"x-smiletoai-scope":"webhooks"},"delete":{"tags":["Webhooks"],"summary":"Delete a webhook endpoint","description":"Removes the endpoint. Deliveries to it stop.","operationId":"delete_endpoint_webhook_endpoints__endpoint_id__delete","parameters":[{"name":"endpoint_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"A webhook endpoint id.","title":"Endpoint Id"},"description":"A webhook endpoint id."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1Deleted"}}}},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Conflict"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Unprocessable Entity"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Too Many Requests"}},"x-smiletoai-scope":"webhooks"}},"/v1/webhook-endpoints/{endpoint_id}/test":{"post":{"tags":["Webhooks"],"summary":"Send a signed ping now","description":"Sends a signed ping event to the endpoint and reports how it answered.","operationId":"test_endpoint_webhook_endpoints__endpoint_id__test_post","parameters":[{"name":"endpoint_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","description":"A webhook endpoint id.","title":"Endpoint Id"},"description":"A webhook endpoint id."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1WebhookTest"}}}},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Unauthorized"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Payment Required"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Conflict"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Unprocessable Entity"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/V1ErrorResponse"}}},"description":"Too Many Requests"}},"x-smiletoai-scope":"webhooks"}}},"components":{"schemas":{"V1Deleted":{"properties":{"object":{"type":"string","const":"deleted","title":"Object","default":"deleted"},"id":{"type":"string","title":"Id","description":"The id of what was deleted."},"deleted":{"type":"boolean","title":"Deleted","default":true}},"additionalProperties":false,"type":"object","required":["id"],"title":"V1Deleted"},"V1ErrorBody":{"properties":{"code":{"type":"string","title":"Code","description":"Machine-readable error code, e.g. insufficient_sparks, plan_upgrade_required, rate_limited."},"message":{"type":"string","title":"Message","description":"What went wrong, in plain English. Do not parse it; branch on code."},"request_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Request Id","description":"The X-Request-Id of this response. Quote it when you contact support."},"errors":{"anyOf":[{"items":{"$ref":"#/components/schemas/V1FieldError"},"type":"array"},{"type":"null"}],"title":"Errors","description":"Per-field (per input slot) problems on a 422."},"details":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Details","description":"Extra context for some codes, e.g. required_scope on insufficient_scope or limit_per_minute on rate_limited."}},"additionalProperties":false,"type":"object","required":["code","message"],"title":"V1ErrorBody"},"V1ErrorResponse":{"properties":{"error":{"$ref":"#/components/schemas/V1ErrorBody"}},"additionalProperties":false,"type":"object","required":["error"],"title":"V1ErrorResponse"},"V1Estimate":{"properties":{"object":{"type":"string","const":"estimate","title":"Object","default":"estimate"},"tool_id":{"type":"string","title":"Tool Id","description":"The tool that was priced."},"product_id":{"type":"string","title":"Product Id","description":"The product the tool runs on."},"sparks":{"type":"integer","title":"Sparks","description":"What the run is expected to cost."},"reserve_sparks":{"type":"integer","title":"Reserve Sparks","description":"What the run holds from the balance while it runs; unused Sparks are refunded."}},"additionalProperties":false,"type":"object","required":["tool_id","product_id","sparks","reserve_sparks"],"title":"V1Estimate"},"V1EstimateHint":{"properties":{"sparks_min":{"type":"integer","title":"Sparks Min","description":"The lowest typical price of a run, in Sparks."},"sparks_max":{"type":"integer","title":"Sparks Max","description":"The highest typical price of a run, in Sparks. Estimate a run for its exact price."}},"additionalProperties":false,"type":"object","required":["sparks_min","sparks_max"],"title":"V1EstimateHint"},"V1EstimateRequest":{"properties":{"inputs":{"additionalProperties":true,"type":"object","title":"Inputs","description":"Slot name to value; media slots take a list of file ids."},"duration_seconds":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"null"}],"title":"Duration Seconds","description":"Length hint for metered video tools before the file is resolved."}},"additionalProperties":false,"type":"object","title":"V1EstimateRequest"},"V1FieldError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Loc","description":"Where the problem is; the last entry names the input slot or field."},"message":{"type":"string","title":"Message","description":"What is wrong, in plain English."},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code","description":"A machine-readable reason, such as workspace_asset_not_found."}},"additionalProperties":false,"type":"object","required":["loc","message"],"title":"V1FieldError"},"V1File":{"properties":{"object":{"type":"string","const":"file","title":"Object","default":"file"},"id":{"type":"string","title":"Id","description":"The file id to use in media inputs."},"status":{"type":"string","title":"Status","description":"The file's state after completion."}},"additionalProperties":false,"type":"object","required":["id","status"],"title":"V1File"},"V1FileCompletePart":{"properties":{"part_number":{"type":"integer","maximum":10000.0,"minimum":1.0,"title":"Part Number","description":"The part's position, as in the upload response."},"etag":{"type":"string","minLength":1,"title":"Etag","description":"The ETag header returned by that part's PUT."}},"additionalProperties":false,"type":"object","required":["part_number","etag"],"title":"V1FileCompletePart"},"V1FileCompleteRequest":{"properties":{"upload_id":{"type":"string","minLength":1,"title":"Upload Id","description":"The upload_id from /v1/files/upload-url."},"parts":{"items":{"$ref":"#/components/schemas/V1FileCompletePart"},"type":"array","minItems":1,"title":"Parts","description":"Every part you uploaded."}},"additionalProperties":false,"type":"object","required":["upload_id","parts"],"title":"V1FileCompleteRequest"},"V1FileUpload":{"properties":{"object":{"type":"string","const":"file_upload","title":"Object","default":"file_upload"},"file_id":{"type":"string","title":"File Id","description":"The file's id. Media inputs take it once the upload is complete."},"upload_id":{"type":"string","title":"Upload Id","description":"Send it back to /v1/files/{file_id}/complete."},"part_size_bytes":{"type":"integer","title":"Part Size Bytes","description":"Bytes per part; the last part may be smaller."},"parts":{"items":{"$ref":"#/components/schemas/V1FileUploadPart"},"type":"array","title":"Parts","description":"PUT each byte range to its URL, keep each response's ETag, then complete."},"expires_in_seconds":{"type":"integer","title":"Expires In Seconds","description":"How long the part URLs work."}},"additionalProperties":false,"type":"object","required":["file_id","upload_id","part_size_bytes","parts","expires_in_seconds"],"title":"V1FileUpload"},"V1FileUploadPart":{"properties":{"part_number":{"type":"integer","title":"Part Number","description":"The part's position, from 1."},"url":{"type":"string","title":"Url","description":"A presigned URL. PUT this part's bytes to it and keep the ETag response header."}},"additionalProperties":false,"type":"object","required":["part_number","url"],"title":"V1FileUploadPart"},"V1FileUploadRequest":{"properties":{"file_name":{"type":"string","maxLength":255,"minLength":1,"title":"File Name","description":"The file's name, e.g. photo.png."},"mime_type":{"type":"string","maxLength":255,"minLength":1,"title":"Mime Type","description":"The file's media type, e.g. image/png."},"size_bytes":{"type":"integer","exclusiveMinimum":0.0,"title":"Size Bytes","description":"The exact size of the file in bytes."}},"additionalProperties":false,"type":"object","required":["file_name","mime_type","size_bytes"],"title":"V1FileUploadRequest"},"V1Me":{"properties":{"object":{"type":"string","const":"me","title":"Object","default":"me"},"team":{"$ref":"#/components/schemas/V1MeTeam","description":"The team the key belongs to."},"api_key":{"$ref":"#/components/schemas/V1MeKey","description":"The key that made this request."},"sparks_available":{"type":"integer","title":"Sparks Available","description":"Sparks the team can spend right now."}},"additionalProperties":false,"type":"object","required":["team","api_key","sparks_available"],"title":"V1Me"},"V1MeKey":{"properties":{"id":{"type":"string","title":"Id","description":"The key's id."},"name":{"type":"string","title":"Name","description":"The name given to the key in Settings."},"prefix":{"type":"string","title":"Prefix","description":"The 8-character prefix shown in Settings."},"scopes":{"items":{"type":"string"},"type":"array","title":"Scopes","description":"Any of read, run and webhooks."},"rate_limit_per_minute":{"type":"integer","title":"Rate Limit Per Minute","description":"Requests per minute this key may make."}},"additionalProperties":false,"type":"object","required":["id","name","prefix","scopes","rate_limit_per_minute"],"title":"V1MeKey"},"V1MeTeam":{"properties":{"id":{"type":"string","title":"Id","description":"The team's id."},"name":{"type":"string","title":"Name","description":"The team's name."},"plan":{"type":"string","title":"Plan","description":"The team's plan, e.g. plus, pro or team."}},"additionalProperties":false,"type":"object","required":["id","name","plan"],"title":"V1MeTeam"},"V1OutputUrl":{"properties":{"object":{"type":"string","const":"output_url","title":"Object","default":"output_url"},"asset_id":{"type":"string","title":"Asset Id","description":"The output this URL downloads."},"url":{"type":"string","title":"Url","description":"A signed download URL. Fetch it straight away."},"expires_in_seconds":{"type":"integer","title":"Expires In Seconds","description":"How long the URL works. Ask again for a fresh one after that."}},"additionalProperties":false,"type":"object","required":["asset_id","url","expires_in_seconds"],"title":"V1OutputUrl"},"V1Run":{"properties":{"object":{"type":"string","const":"run","title":"Object","default":"run"},"id":{"type":"string","title":"Id","description":"The run id, for GET /v1/runs/{run_id}."},"tool_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tool Id","description":"The tool that runs."},"product_id":{"type":"string","title":"Product Id","description":"The product the tool runs on."},"status":{"type":"string","enum":["queued","running","succeeded","failed","canceled"],"title":"Status","description":"succeeded, failed and canceled are final; poll until you see one of them."},"progress":{"type":"number","title":"Progress","description":"From 0 to 1 while the run works."},"cost_sparks":{"type":"integer","title":"Cost Sparks","description":"The hold while the run is in flight; what was charged once it is terminal."},"outputs":{"items":{"$ref":"#/components/schemas/V1RunOutput"},"type":"array","title":"Outputs","description":"The files a succeeded run produced; empty until then."},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"Why a failed run failed."},"api_key_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Key Id","description":"The API key that started the run."},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At","description":"When the run was started (ISO 8601, UTC)."},"started_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Started At","description":"When work began (ISO 8601, UTC)."},"finished_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Finished At","description":"When the run reached a final status (ISO 8601, UTC)."}},"additionalProperties":false,"type":"object","required":["id","tool_id","product_id","status","progress","cost_sparks","outputs","error","api_key_id","created_at","started_at","finished_at"],"title":"V1Run"},"V1RunOutput":{"properties":{"asset_id":{"type":"string","title":"Asset Id","description":"Pass it to /v1/runs/{run_id}/outputs/{asset_id}/url to download the file."},"mime_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mime Type","description":"The file's media type, e.g. image/png."},"width":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Width","description":"Pixel width of an image or video."},"height":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Height","description":"Pixel height of an image or video."},"duration_seconds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Duration Seconds","description":"Length of a video or audio file."},"size_bytes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Size Bytes","description":"File size in bytes."},"file_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Name","description":"A suggested file name."}},"additionalProperties":false,"type":"object","required":["asset_id"],"title":"V1RunOutput"},"V1RunRequest":{"properties":{"inputs":{"additionalProperties":true,"type":"object","title":"Inputs","description":"Slot name to value; media slots take a list of file ids."},"duration_seconds":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"null"}],"title":"Duration Seconds","description":"Length hint for metered video tools before the file is resolved."}},"additionalProperties":false,"type":"object","title":"V1RunRequest"},"V1Tool":{"properties":{"object":{"type":"string","const":"tool","title":"Object","default":"tool"},"id":{"type":"string","title":"Id","description":"The tool id used in /v1/tools/{tool_id}/estimate and /runs, e.g. image_upscale."},"name":{"type":"string","title":"Name","description":"The tool's display name."},"description":{"type":"string","title":"Description","description":"What the tool does."},"family":{"type":"string","title":"Family","description":"The tool's group, e.g. enhance, edit or analyze."},"inputs":{"items":{"$ref":"#/components/schemas/V1ToolInput"},"type":"array","title":"Inputs","description":"The input slots a run takes."},"output_kind":{"type":"string","title":"Output Kind","description":"What a run produces: image, video, audio or json."},"consent":{"type":"string","title":"Consent","description":"none, voice or face. Identity tools need an element with active consent."},"allowed":{"type":"boolean","title":"Allowed","description":"False when the team's plan does not include this tool."},"estimate_hint":{"$ref":"#/components/schemas/V1EstimateHint","description":"A typical price range. Estimate a run for its exact price."}},"additionalProperties":false,"type":"object","required":["id","name","description","family","inputs","output_kind","consent","allowed","estimate_hint"],"title":"V1Tool"},"V1ToolInput":{"properties":{"name":{"type":"string","title":"Name","description":"The slot name, used as the key in inputs."},"kind":{"type":"string","title":"Kind","description":"image, video, audio, text, element, enum, number or bool. Media slots take file ids."},"required":{"type":"boolean","title":"Required","description":"Whether a run needs this slot."},"min":{"type":"integer","title":"Min","description":"The fewest values the slot takes (media slots take a list)."},"max":{"type":"integer","title":"Max","description":"The most values the slot takes."},"constraints":{"additionalProperties":true,"type":"object","title":"Constraints","description":"Extra limits for the slot, such as a number range."},"choices":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Choices","description":"The allowed values of an enum slot."},"default":{"title":"Default","description":"The value used when the slot is left out."}},"additionalProperties":false,"type":"object","required":["name","kind","required","min","max"],"title":"V1ToolInput"},"V1ToolList":{"properties":{"object":{"type":"string","const":"list","title":"Object","default":"list"},"data":{"items":{"$ref":"#/components/schemas/V1Tool"},"type":"array","title":"Data","description":"Tools available over the API that this key can see."}},"additionalProperties":false,"type":"object","required":["data"],"title":"V1ToolList"},"V1WebhookEndpoint":{"properties":{"object":{"type":"string","const":"webhook_endpoint","title":"Object","default":"webhook_endpoint"},"id":{"type":"string","title":"Id","description":"The endpoint's id."},"url":{"type":"string","title":"Url","description":"Where deliveries are POSTed."},"events":{"items":{"type":"string"},"type":"array","title":"Events","description":"Any of run.succeeded, run.failed and run.canceled."},"enabled":{"type":"boolean","title":"Enabled","description":"A paused endpoint receives nothing, and runs that finish while it is paused are not sent later."},"created_at":{"type":"string","title":"Created At","description":"When the endpoint was added (ISO 8601, UTC)."}},"additionalProperties":false,"type":"object","required":["id","url","events","enabled","created_at"],"title":"V1WebhookEndpoint"},"V1WebhookEndpointCreateRequest":{"properties":{"url":{"type":"string","maxLength":2048,"title":"Url","description":"An HTTPS URL on a public host."},"events":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Events","description":"Any of run.succeeded, run.failed, run.canceled; all three when omitted."}},"additionalProperties":false,"type":"object","required":["url"],"title":"V1WebhookEndpointCreateRequest"},"V1WebhookEndpointCreated":{"properties":{"object":{"type":"string","const":"webhook_endpoint","title":"Object","default":"webhook_endpoint"},"id":{"type":"string","title":"Id","description":"The endpoint's id."},"url":{"type":"string","title":"Url","description":"Where deliveries are POSTed."},"events":{"items":{"type":"string"},"type":"array","title":"Events","description":"Any of run.succeeded, run.failed and run.canceled."},"enabled":{"type":"boolean","title":"Enabled","description":"A paused endpoint receives nothing, and runs that finish while it is paused are not sent later."},"created_at":{"type":"string","title":"Created At","description":"When the endpoint was added (ISO 8601, UTC)."},"signing_secret":{"type":"string","title":"Signing Secret","description":"Shown once. Verify SmileToAI-Signature with it."}},"additionalProperties":false,"type":"object","required":["id","url","events","enabled","created_at","signing_secret"],"title":"V1WebhookEndpointCreated"},"V1WebhookEndpointList":{"properties":{"object":{"type":"string","const":"list","title":"Object","default":"list"},"data":{"items":{"$ref":"#/components/schemas/V1WebhookEndpoint"},"type":"array","title":"Data","description":"The team's webhook endpoints."}},"additionalProperties":false,"type":"object","required":["data"],"title":"V1WebhookEndpointList"},"V1WebhookEndpointUpdateRequest":{"properties":{"enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Enabled","description":"false pauses the endpoint and drops its pending deliveries; true resumes it."},"events":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Events","description":"Replaces the endpoint's events."}},"additionalProperties":false,"type":"object","title":"V1WebhookEndpointUpdateRequest"},"V1WebhookTest":{"properties":{"object":{"type":"string","const":"webhook_test","title":"Object","default":"webhook_test"},"delivery_id":{"type":"string","title":"Delivery Id","description":"The SmileToAI-Delivery header of the ping."},"delivered":{"type":"boolean","title":"Delivered","description":"Whether your endpoint answered with a 2xx."},"response_code":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Response Code","description":"The HTTP status your endpoint answered with."},"duration_ms":{"type":"integer","title":"Duration Ms","description":"How long the delivery took."},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"Why the delivery failed, if it did."}},"additionalProperties":false,"type":"object","required":["delivery_id","delivered","response_code","duration_ms","error"],"title":"V1WebhookTest"}},"securitySchemes":{"ApiKey":{"type":"http","scheme":"bearer","bearerFormat":"stai_live_<prefix>_<secret>","description":"A team API key from Settings > API keys."}}},"security":[{"ApiKey":[]}]}