DevelopersAPI reference

API reference

Every /v1 route, built from the OpenAPI document the API serves. New to the API? Start with the guide.

Base URL
https://api.smiletoai.com
Auth header
Bearer stai_live_…
Version
1.0.0, OpenAPI 3.1
Download
openapi.json

Account

Who you are calling as.

GET/v1/me

The team and key behind this request

Check that a key works and see the team, plan, scopes and rate limit it carries, and the Sparks the team can spend.

ScopereadReturns200

Response 200

  • teamobjectrequired

    The team the key belongs to.

  • team.idstringrequired

    The team's id.

  • team.namestringrequired

    The team's name.

  • team.planstringrequired

    The team's plan, e.g. plus, pro or team.

  • api_keyobjectrequired

    The key that made this request.

  • api_key.idstringrequired

    The key's id.

  • api_key.namestringrequired

    The name given to the key in Settings.

  • api_key.prefixstringrequired

    The 8-character prefix shown in Settings.

  • api_key.scopesarray of stringsrequired

    Any of read, run and webhooks.

  • api_key.rate_limit_per_minuteintegerrequired

    Requests per minute this key may make.

  • sparks_availableintegerrequired

    Sparks the team can spend right now.

Errors use one shape across the API. See the error codes

curl https://api.smiletoai.com/v1/me \
  -H "Authorization: Bearer $SMILETOAI_KEY"
200ResponseExample
{
  "object": "me",
  "team": {
    "id": "6f0c2d9a-3b1e-4f57-9a0d-2c8e5b7f1a64",
    "name": "Northwind Studio",
    "plan": "pro"
  },
  "api_key": {
    "id": "a3e1b0c4-5d2f-4e8a-b7c9-0f1e2d3c4b5a",
    "name": "Production",
    "prefix": "k7m2p9qa",
    "scopes": [
      "read",
      "run"
    ],
    "rate_limit_per_minute": 60
  },
  "sparks_available": 84210
}

Tools

What you can run, what it costs, and starting a run.

GET/v1/tools

List the tools this key can run

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.

ScopereadReturns200

Response 200

  • dataarray of objectsrequired

    Tools available over the API that this key can see.

  • data[].idstringrequired

    The tool id used in /v1/tools/{tool_id}/estimate and /runs, e.g. image_upscale.

  • data[].namestringrequired

    The tool's display name.

  • data[].descriptionstringrequired

    What the tool does.

  • data[].familystringrequired

    The tool's group, e.g. enhance, edit or analyze.

  • data[].inputsarray of objectsrequired

    The input slots a run takes.

  • data[].output_kindstringrequired

    What a run produces: image, video, audio or json.

  • data[].consentstringrequired

    none, voice or face. Identity tools need an element with active consent.

  • data[].allowedbooleanrequired

    False when the team's plan does not include this tool.

  • data[].estimate_hintobjectrequired

    A typical price range. Estimate a run for its exact price.

Errors use one shape across the API. See the error codes

curl https://api.smiletoai.com/v1/tools \
  -H "Authorization: Bearer $SMILETOAI_KEY"
200ResponseExample
{
  "object": "list",
  "data": [
    {
      "object": "tool",
      "id": "image_upscale",
      "name": "Upscale image",
      "description": "Upscale image enlarges and sharpens an image with an AI super-resolution model (up to 4096 px on the long side).",
      "family": "enhance",
      "inputs": [
        {
          "name": "image",
          "kind": "image",
          "required": true,
          "min": 1,
          "max": 1,
          "constraints": {
            "max_pixels": 16000000,
            "mime_types": [
              "image/png",
              "image/jpeg",
              "image/webp"
            ]
          },
          "choices": null,
          "default": null
        }
      ],
      "output_kind": "image",
      "consent": "none",
      "allowed": true,
      "estimate_hint": {
        "sparks_min": 30,
        "sparks_max": 30
      }
    }
  ]
}
POST/v1/tools/{tool_id}/estimate

Price a run without starting it

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.

ScopereadReturns200

Parameters

  • tool_idpath · stringrequired

    A tool id from GET /v1/tools, such as image_upscale.

Body

  • inputsobject

    Slot name to value; media slots take a list of file ids.

  • duration_secondsnumber

    Length hint for metered video tools before the file is resolved.

Response 200

  • tool_idstringrequired

    The tool that was priced.

  • product_idstringrequired

    The product the tool runs on.

  • sparksintegerrequired

    What the run is expected to cost.

  • reserve_sparksintegerrequired

    What the run holds from the balance while it runs; unused Sparks are refunded.

Errors use one shape across the API. See the error codes

curl -X POST https://api.smiletoai.com/v1/tools/image_upscale/estimate \
  -H "Authorization: Bearer $SMILETOAI_KEY" \
  -H "Content-Type: application/json" \
  -d '{"inputs": {"image": ["9d41e2c7-0b8a-4f3e-a1d5-6c7b8e9f0a12"]}}'
200ResponseExample
{
  "object": "estimate",
  "tool_id": "image_upscale",
  "product_id": "image_upscale",
  "sparks": 30,
  "reserve_sparks": 30
}
POST/v1/tools/{tool_id}/runs

Start a run (it spends the team's Sparks)

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.

ScoperunReturns202

Parameters

  • tool_idpath · stringrequired

    A tool id from GET /v1/tools, such as image_upscale.

  • Idempotency-Keyheader · string

    Any string up to 255 characters. Sending the same key again returns the run it already started.

Body

  • inputsobject

    Slot name to value; media slots take a list of file ids.

  • duration_secondsnumber

    Length hint for metered video tools before the file is resolved.

Response 202

  • idstringrequired

    The run id, for GET /v1/runs/{run_id}.

  • tool_idstringrequired

    The tool that runs.

  • product_idstringrequired

    The product the tool runs on.

  • status"queued" | "running" | "succeeded" | "failed" | "canceled"required

    succeeded, failed and canceled are final; poll until you see one of them.

  • progressnumberrequired

    From 0 to 1 while the run works.

  • cost_sparksintegerrequired

    The hold while the run is in flight; what was charged once it is terminal.

  • outputsarray of objectsrequired

    The files a succeeded run produced; empty until then.

  • outputs[].asset_idstringrequired

    Pass it to /v1/runs/{run_id}/outputs/{asset_id}/url to download the file.

  • outputs[].mime_typestring

    The file's media type, e.g. image/png.

  • outputs[].widthinteger

    Pixel width of an image or video.

  • outputs[].heightinteger

    Pixel height of an image or video.

  • outputs[].duration_secondsnumber

    Length of a video or audio file.

  • outputs[].size_bytesinteger

    File size in bytes.

  • outputs[].file_namestring

    A suggested file name.

  • errorstringrequired

    Why a failed run failed.

  • api_key_idstringrequired

    The API key that started the run.

  • created_atstringrequired

    When the run was started (ISO 8601, UTC).

  • started_atstringrequired

    When work began (ISO 8601, UTC).

  • finished_atstringrequired

    When the run reached a final status (ISO 8601, UTC).

Errors use one shape across the API. See the error codes

curl -X POST https://api.smiletoai.com/v1/tools/image_upscale/runs \
  -H "Authorization: Bearer $SMILETOAI_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-1042" \
  -d '{"inputs": {"image": ["9d41e2c7-0b8a-4f3e-a1d5-6c7b8e9f0a12"]}}'
202ResponseExample
{
  "object": "run",
  "id": "8f2c0b7e-41d6-4c1a-9e55-2b7d1f0c9a31",
  "tool_id": "image_upscale",
  "product_id": "image_upscale",
  "status": "queued",
  "progress": 0,
  "cost_sparks": 30,
  "outputs": [],
  "error": null,
  "api_key_id": "a3e1b0c4-5d2f-4e8a-b7c9-0f1e2d3c4b5a",
  "created_at": "2026-10-17T09:12:03Z",
  "started_at": null,
  "finished_at": null
}

Runs

Reading, canceling and downloading the runs your keys started.

GET/v1/runs/{run_id}

Get a run

Only runs started with this team's API keys. Poll every 2 to 5 seconds until the status is succeeded, failed or canceled.

ScopereadReturns200

Parameters

  • run_idpath · stringrequired

    The id of a run started with one of your team's API keys.

Response 200

  • idstringrequired

    The run id, for GET /v1/runs/{run_id}.

  • tool_idstringrequired

    The tool that runs.

  • product_idstringrequired

    The product the tool runs on.

  • status"queued" | "running" | "succeeded" | "failed" | "canceled"required

    succeeded, failed and canceled are final; poll until you see one of them.

  • progressnumberrequired

    From 0 to 1 while the run works.

  • cost_sparksintegerrequired

    The hold while the run is in flight; what was charged once it is terminal.

  • outputsarray of objectsrequired

    The files a succeeded run produced; empty until then.

  • outputs[].asset_idstringrequired

    Pass it to /v1/runs/{run_id}/outputs/{asset_id}/url to download the file.

  • outputs[].mime_typestring

    The file's media type, e.g. image/png.

  • outputs[].widthinteger

    Pixel width of an image or video.

  • outputs[].heightinteger

    Pixel height of an image or video.

  • outputs[].duration_secondsnumber

    Length of a video or audio file.

  • outputs[].size_bytesinteger

    File size in bytes.

  • outputs[].file_namestring

    A suggested file name.

  • errorstringrequired

    Why a failed run failed.

  • api_key_idstringrequired

    The API key that started the run.

  • created_atstringrequired

    When the run was started (ISO 8601, UTC).

  • started_atstringrequired

    When work began (ISO 8601, UTC).

  • finished_atstringrequired

    When the run reached a final status (ISO 8601, UTC).

Errors use one shape across the API. See the error codes

curl https://api.smiletoai.com/v1/runs/8f2c0b7e-41d6-4c1a-9e55-2b7d1f0c9a31 \
  -H "Authorization: Bearer $SMILETOAI_KEY"
200ResponseExample
{
  "object": "run",
  "id": "8f2c0b7e-41d6-4c1a-9e55-2b7d1f0c9a31",
  "tool_id": "image_upscale",
  "product_id": "image_upscale",
  "status": "succeeded",
  "progress": 1,
  "cost_sparks": 30,
  "outputs": [
    {
      "asset_id": "c71a5e02-9b4d-4e1f-8a3c-5d6e7f8091a2",
      "mime_type": "image/png",
      "width": 4096,
      "height": 4096,
      "duration_seconds": null,
      "size_bytes": 9420117,
      "file_name": "photo-upscaled.png"
    }
  ],
  "error": null,
  "api_key_id": "a3e1b0c4-5d2f-4e8a-b7c9-0f1e2d3c4b5a",
  "created_at": "2026-10-17T09:12:03Z",
  "started_at": "2026-10-17T09:12:05Z",
  "finished_at": "2026-10-17T09:12:41Z"
}
POST/v1/runs/{run_id}/cancel

Cancel a queued or running run

Stops the run and releases its hold, as canceling in the app does.

ScoperunReturns200

Parameters

  • run_idpath · stringrequired

    The id of a run started with one of your team's API keys.

Response 200

  • idstringrequired

    The run id, for GET /v1/runs/{run_id}.

  • tool_idstringrequired

    The tool that runs.

  • product_idstringrequired

    The product the tool runs on.

  • status"queued" | "running" | "succeeded" | "failed" | "canceled"required

    succeeded, failed and canceled are final; poll until you see one of them.

  • progressnumberrequired

    From 0 to 1 while the run works.

  • cost_sparksintegerrequired

    The hold while the run is in flight; what was charged once it is terminal.

  • outputsarray of objectsrequired

    The files a succeeded run produced; empty until then.

  • outputs[].asset_idstringrequired

    Pass it to /v1/runs/{run_id}/outputs/{asset_id}/url to download the file.

  • outputs[].mime_typestring

    The file's media type, e.g. image/png.

  • outputs[].widthinteger

    Pixel width of an image or video.

  • outputs[].heightinteger

    Pixel height of an image or video.

  • outputs[].duration_secondsnumber

    Length of a video or audio file.

  • outputs[].size_bytesinteger

    File size in bytes.

  • outputs[].file_namestring

    A suggested file name.

  • errorstringrequired

    Why a failed run failed.

  • api_key_idstringrequired

    The API key that started the run.

  • created_atstringrequired

    When the run was started (ISO 8601, UTC).

  • started_atstringrequired

    When work began (ISO 8601, UTC).

  • finished_atstringrequired

    When the run reached a final status (ISO 8601, UTC).

Errors use one shape across the API. See the error codes

curl -X POST https://api.smiletoai.com/v1/runs/8f2c0b7e-41d6-4c1a-9e55-2b7d1f0c9a31/cancel \
  -H "Authorization: Bearer $SMILETOAI_KEY"
200ResponseExample
{
  "object": "run",
  "id": "8f2c0b7e-41d6-4c1a-9e55-2b7d1f0c9a31",
  "tool_id": "image_upscale",
  "product_id": "image_upscale",
  "status": "canceled",
  "progress": 0,
  "cost_sparks": 0,
  "outputs": [],
  "error": null,
  "api_key_id": "a3e1b0c4-5d2f-4e8a-b7c9-0f1e2d3c4b5a",
  "created_at": "2026-10-17T09:12:03Z",
  "started_at": null,
  "finished_at": "2026-10-17T09:12:09Z"
}
GET/v1/runs/{run_id}/outputs/{asset_id}/url

Get a short-lived download URL for an output

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.

ScopereadReturns200

Parameters

  • run_idpath · stringrequired

    The id of a run started with one of your team's API keys.

  • asset_idpath · stringrequired

    An asset_id from the run's outputs.

Response 200

  • asset_idstringrequired

    The output this URL downloads.

  • urlstringrequired

    A signed download URL. Fetch it straight away.

  • expires_in_secondsintegerrequired

    How long the URL works. Ask again for a fresh one after that.

Errors use one shape across the API. See the error codes

curl https://api.smiletoai.com/v1/runs/8f2c0b7e-41d6-4c1a-9e55-2b7d1f0c9a31/outputs/c71a5e02-9b4d-4e1f-8a3c-5d6e7f8091a2/url \
  -H "Authorization: Bearer $SMILETOAI_KEY"
200ResponseExample
{
  "object": "output_url",
  "asset_id": "c71a5e02-9b4d-4e1f-8a3c-5d6e7f8091a2",
  "url": "https://storage.example.com/c71a5e02-9b4d-4e1f-8a3c-5d6e7f8091a2.png?signature=…",
  "expires_in_seconds": 600
}

Files

Uploading the files media inputs take.

POST/v1/files/upload-url

Start a file upload

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.

ScoperunReturns201

Body

  • file_namestringrequired

    The file's name, e.g. photo.png.

  • mime_typestringrequired

    The file's media type, e.g. image/png.

  • size_bytesintegerrequired

    The exact size of the file in bytes.

Response 201

  • file_idstringrequired

    The file's id. Media inputs take it once the upload is complete.

  • upload_idstringrequired

    Send it back to /v1/files/{file_id}/complete.

  • part_size_bytesintegerrequired

    Bytes per part; the last part may be smaller.

  • partsarray of objectsrequired

    PUT each byte range to its URL, keep each response's ETag, then complete.

  • parts[].part_numberintegerrequired

    The part's position, from 1.

  • parts[].urlstringrequired

    A presigned URL. PUT this part's bytes to it and keep the ETag response header.

  • expires_in_secondsintegerrequired

    How long the part URLs work.

Errors use one shape across the API. See the error codes

curl -X POST https://api.smiletoai.com/v1/files/upload-url \
  -H "Authorization: Bearer $SMILETOAI_KEY" \
  -H "Content-Type: application/json" \
  -d '{"file_name": "photo.png", "mime_type": "image/png", "size_bytes": 482113}'
201ResponseExample
{
  "object": "file_upload",
  "file_id": "9d41e2c7-0b8a-4f3e-a1d5-6c7b8e9f0a12",
  "upload_id": "cGhvdG8tdXBsb2FkLTE",
  "part_size_bytes": 8388608,
  "parts": [
    {
      "part_number": 1,
      "url": "https://storage.example.com/uploads/photo.png?partNumber=1&signature=…"
    }
  ],
  "expires_in_seconds": 900
}
POST/v1/files/{file_id}/complete

Finish a file upload

Completes the upload with every part's ETag. The file id then works in media inputs.

ScoperunReturns200

Parameters

  • file_idpath · stringrequired

    The file_id from POST /v1/files/upload-url.

Body

  • upload_idstringrequired

    The upload_id from /v1/files/upload-url.

  • partsarray of objectsrequired

    Every part you uploaded.

  • parts[].part_numberintegerrequired

    The part's position, as in the upload response.

  • parts[].etagstringrequired

    The ETag header returned by that part's PUT.

Response 200

  • idstringrequired

    The file id to use in media inputs.

  • statusstringrequired

    The file's state after completion.

Errors use one shape across the API. See the error codes

curl -X POST https://api.smiletoai.com/v1/files/9d41e2c7-0b8a-4f3e-a1d5-6c7b8e9f0a12/complete \
  -H "Authorization: Bearer $SMILETOAI_KEY" \
  -H "Content-Type: application/json" \
  -d '{"upload_id": "cGhvdG8tdXBsb2FkLTE", "parts": [{"part_number": 1, "etag": "\"5d41402abc4b2a76b9719d911017c592\""}]}'
200ResponseExample
{
  "object": "file",
  "id": "9d41e2c7-0b8a-4f3e-a1d5-6c7b8e9f0a12",
  "status": "uploaded"
}

Webhooks

Managing the endpoints that receive run events.

GET/v1/webhook-endpoints

List webhook endpoints

The team's endpoints. The key's creator must be a team owner or admin.

ScopewebhooksReturns200

Response 200

  • dataarray of objectsrequired

    The team's webhook endpoints.

  • data[].idstringrequired

    The endpoint's id.

  • data[].urlstringrequired

    Where deliveries are POSTed.

  • data[].eventsarray of stringsrequired

    Any of run.succeeded, run.failed and run.canceled.

  • data[].enabledbooleanrequired

    A paused endpoint receives nothing, and runs that finish while it is paused are not sent later.

  • data[].created_atstringrequired

    When the endpoint was added (ISO 8601, UTC).

Errors use one shape across the API. See the error codes

curl https://api.smiletoai.com/v1/webhook-endpoints \
  -H "Authorization: Bearer $SMILETOAI_KEY"
200ResponseExample
{
  "object": "list",
  "data": [
    {
      "object": "webhook_endpoint",
      "id": "4b8e2f10-7c3d-4a9e-b5f6-1d2c3e4f5a6b",
      "url": "https://example.com/hooks/smiletoai",
      "events": [
        "run.succeeded",
        "run.failed",
        "run.canceled"
      ],
      "enabled": true,
      "created_at": "2026-10-17T08:40:00Z"
    }
  ]
}
POST/v1/webhook-endpoints

Add a webhook endpoint

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.

ScopewebhooksReturns201

Body

  • urlstringrequired

    An HTTPS URL on a public host.

  • eventsarray of strings

    Any of run.succeeded, run.failed, run.canceled; all three when omitted.

Response 201

  • idstringrequired

    The endpoint's id.

  • urlstringrequired

    Where deliveries are POSTed.

  • eventsarray of stringsrequired

    Any of run.succeeded, run.failed and run.canceled.

  • enabledbooleanrequired

    A paused endpoint receives nothing, and runs that finish while it is paused are not sent later.

  • created_atstringrequired

    When the endpoint was added (ISO 8601, UTC).

  • signing_secretstringrequired

    Shown once. Verify SmileToAI-Signature with it.

Errors use one shape across the API. See the error codes

curl -X POST https://api.smiletoai.com/v1/webhook-endpoints \
  -H "Authorization: Bearer $SMILETOAI_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/hooks/smiletoai", "events": ["run.succeeded", "run.failed"]}'
201ResponseExample
{
  "object": "webhook_endpoint",
  "id": "4b8e2f10-7c3d-4a9e-b5f6-1d2c3e4f5a6b",
  "url": "https://example.com/hooks/smiletoai",
  "events": [
    "run.succeeded",
    "run.failed"
  ],
  "enabled": true,
  "created_at": "2026-10-17T08:40:00Z",
  "signing_secret": "whsec_…"
}
PATCH/v1/webhook-endpoints/{endpoint_id}

Pause, resume or change events

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.

ScopewebhooksReturns200

Parameters

  • endpoint_idpath · stringrequired

    A webhook endpoint id.

Body

  • enabledboolean

    false pauses the endpoint and drops its pending deliveries; true resumes it.

  • eventsarray of strings

    Replaces the endpoint's events.

Response 200

  • idstringrequired

    The endpoint's id.

  • urlstringrequired

    Where deliveries are POSTed.

  • eventsarray of stringsrequired

    Any of run.succeeded, run.failed and run.canceled.

  • enabledbooleanrequired

    A paused endpoint receives nothing, and runs that finish while it is paused are not sent later.

  • created_atstringrequired

    When the endpoint was added (ISO 8601, UTC).

Errors use one shape across the API. See the error codes

curl -X PATCH https://api.smiletoai.com/v1/webhook-endpoints/4b8e2f10-7c3d-4a9e-b5f6-1d2c3e4f5a6b \
  -H "Authorization: Bearer $SMILETOAI_KEY" \
  -H "Content-Type: application/json" \
  -d '{"enabled": false}'
200ResponseExample
{
  "object": "webhook_endpoint",
  "id": "4b8e2f10-7c3d-4a9e-b5f6-1d2c3e4f5a6b",
  "url": "https://example.com/hooks/smiletoai",
  "events": [
    "run.succeeded",
    "run.failed",
    "run.canceled"
  ],
  "enabled": false,
  "created_at": "2026-10-17T08:40:00Z"
}
DELETE/v1/webhook-endpoints/{endpoint_id}

Delete a webhook endpoint

Removes the endpoint. Deliveries to it stop.

ScopewebhooksReturns200

Parameters

  • endpoint_idpath · stringrequired

    A webhook endpoint id.

Response 200

  • idstringrequired

    The id of what was deleted.

  • deletedboolean

Errors use one shape across the API. See the error codes

curl -X DELETE https://api.smiletoai.com/v1/webhook-endpoints/4b8e2f10-7c3d-4a9e-b5f6-1d2c3e4f5a6b \
  -H "Authorization: Bearer $SMILETOAI_KEY"
200ResponseExample
{
  "object": "deleted",
  "id": "4b8e2f10-7c3d-4a9e-b5f6-1d2c3e4f5a6b",
  "deleted": true
}
POST/v1/webhook-endpoints/{endpoint_id}/test

Send a signed ping now

Sends a signed ping event to the endpoint and reports how it answered.

ScopewebhooksReturns200

Parameters

  • endpoint_idpath · stringrequired

    A webhook endpoint id.

Response 200

  • delivery_idstringrequired

    The SmileToAI-Delivery header of the ping.

  • deliveredbooleanrequired

    Whether your endpoint answered with a 2xx.

  • response_codeintegerrequired

    The HTTP status your endpoint answered with.

  • duration_msintegerrequired

    How long the delivery took.

  • errorstringrequired

    Why the delivery failed, if it did.

Errors use one shape across the API. See the error codes

curl -X POST https://api.smiletoai.com/v1/webhook-endpoints/4b8e2f10-7c3d-4a9e-b5f6-1d2c3e4f5a6b/test \
  -H "Authorization: Bearer $SMILETOAI_KEY"
200ResponseExample
{
  "object": "webhook_test",
  "delivery_id": "2b9e47d1-6a5c-4f8b-9e0d-3c2b1a0f9e8d",
  "delivered": true,
  "response_code": 200,
  "duration_ms": 182,
  "error": null
}