REST API

Presets

List presets and their templates, then run one through POST /generations with config.template_id.

Read as Markdown

A preset is a ready-made recipe, such as Show Your App or Fashion Try On. It is a capability with a preset_ id, so it is priced with POST /estimates and run with POST /generations like any other. What these two routes add is the template list: a template-driven preset has a required config.template_id, and this is where its legal values come from.

EndpointScopeRate limit per keyWhat it does
GET /presetsRead120 a minute (agent_read)Every preset this workspace can see, each with its first 20 templates
GET /presets/{id}/templatesRead120 a minute (agent_read)One preset's whole template gallery
  • Both are reads. They cost nothing.
  • MCP: list_presets (pass capability_id for one preset's full gallery). MCP tools.

A preset is not a separate submit path

There is no preset endpoint that starts work. You run a preset with POST /generations, capability_id set to its preset_ id, and config.template_id set to a template_id from these lists.

List presets

GET/api/v1/presetsAPI key
ParameterTypeDefaultNotes
limitinteger25Clamped to 1 to 50
cursorstringnoneThe previous next_cursor, sent back exactly
Terminal
curl -s https://app.riffads.com/api/v1/presets \
  -H "Authorization: Bearer $RIFFADS_API_KEY"
Response: 200 (trimmed)
{
  "ok": true,
  "presets": [
    {
      "capability_id": "preset_show_your_app",
      "name": "Show Your App",
      "description": "Put your app screenshot on a real person's phone, then bring it to life.",
      "output_kind": "video",
      "status": "available",
      "requires_template": true,
      "templates": [
        {
          "template_id": "captpl_0193c8f0a1b24e7f9d3c5a6b7e8f00a1",
          "name": "Couch scroll",
          "description": "Relaxed, at home, thumb on the screen",
          "category": "Lifestyle",
          "preview_url": "https://<public-preview-host>/templates/couch-scroll.mp4",
          "preview_kind": "video"
        }
      ],
      "templates_total": 1,
      "next_action": "Call get_capability_schema with capability_id \"preset_show_your_app\" to see its other fields, then call submit_generation with capability_id \"preset_show_your_app\" and config.template_id set to one of the template_id values listed with it. A preset is not a separate tool: submit_generation runs it like any other capability."
    }
  ],
  "total": 2,
  "next_cursor": null
}

Template names, counts and ids are examples. Read the live list, never hardcode one.

Preset fields

FieldTypeNotes
capability_idstringpreset_ prefix. Send it as capability_id to estimate and submit
namestringDisplay name. Can change. Never match on it
descriptionstringOmitted, not null, when empty
output_kindimage | video | audio | textWhat comes out
statusavailable | requires_plan | coming_soonOnly available can run. Retired presets are not listed
required_planstringOnly with requires_plan. The plan that includes it
requires_templatebooleantrue: config.template_id is required, so pick one of templates
templatesarrayThe first 20 live templates, in gallery order
templates_totalintegerAll live templates. More than templates.length means this row is capped
next_actionstringHow to run it, written for an agent. Advice only
  • Order and cursor: the same as GET /capabilities. next_cursor is the last row's capability_id, and null on the last page.
  • total counts the presets this workspace can see.
  • requires_template: true with templates_total: 0 means the preset cannot run right now. Its next_action says so.

Template fields

FieldTypeNotes
template_idstringcaptpl_ prefix. The value for config.template_id
namestringDisplay name
descriptionstring | null
categorystring | nullGallery grouping. Free text: display only
preview_urlstringA permanent public preview of RiffAds' own template art. Not a signed link, and it does not expire
preview_kindvideo | imageWhat preview_url holds

A template id is a database id, not a slug

Read it from these routes every time. An id copied from an old list can be withdrawn by the time you submit, and the answer is then a refusal, not a render.

One preset's templates

GET/api/v1/presets/{id}/templatesAPI key

The path id is a preset capability_id. Returns every live template, with no cap and no paging.

Terminal
curl -s https://app.riffads.com/api/v1/presets/preset_show_your_app/templates \
  -H "Authorization: Bearer $RIFFADS_API_KEY"
Response: 200 (templates trimmed)
{
  "ok": true,
  "capability_id": "preset_show_your_app",
  "name": "Show Your App",
  "status": "available",
  "requires_template": true,
  "templates": [
    {
      "template_id": "captpl_0193c8f0a1b24e7f9d3c5a6b7e8f00a1",
      "name": "Couch scroll",
      "description": "Relaxed, at home, thumb on the screen",
      "category": "Lifestyle",
      "preview_url": "https://<public-preview-host>/templates/couch-scroll.mp4",
      "preview_kind": "video"
    }
  ],
  "next_action": "Call get_capability_schema with capability_id \"preset_show_your_app\" to see its other fields, then call submit_generation with capability_id \"preset_show_your_app\" and config.template_id set to one of the template_id values listed with it. A preset is not a separate tool: submit_generation runs it like any other capability."
}

required_plan appears only when status is requires_plan.

Response: 404
{
  "error": {
    "ok": false,
    "code": "not_found",
    "message": "No such preset. Call list_presets for the presets this workspace can use, or list_capabilities for everything else.",
    "retryable": false,
    "credits_charged": 0
  }
}

not_found covers a non-preset id (like veo_31), a typo, and a retired or internal preset.

REST names for the MCP tools in next_action

next_action is written for an agent and names MCP tools. Over REST:

next_action saysREST call
get_capability_schemaGET /capabilities/{id}
submit_generationPOST /generations
list_presets with capability_idGET /presets/{id}/templates
list_capabilitiesGET /capabilities

Run a preset

Show Your App puts your app's screenshot on the phone a creator is holding. One upload plus one template.

Pick a template

GET /presets/preset_show_your_app/templates. Show the person the preview_url of each and keep the template_id they choose.

Read the schema

GET /capabilities/preset_show_your_app. It lists template_id and reference_images as required. Locked preset settings are absent: they come from the template. Capabilities API.

Upload the screenshot

POST /uploads, PUT the bytes, finalize, and keep the ast_ id. Uploads.

Estimate

Terminal
curl -s https://app.riffads.com/api/v1/estimates \
  -H "Authorization: Bearer $RIFFADS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "capability_id": "preset_show_your_app",
    "config": {
      "template_id": "captpl_0193c8f0a1b24e7f9d3c5a6b7e8f00a1",
      "reference_images": [
        { "assetId": "ast_0193c8f0a1b24e7f9d3c5a6b7e8f0011", "alias": "image1", "role": "reference" }
      ]
    }
  }'

The estimate checks the config exactly as submit does, so a wrong key or a missing template_id is refused here, before anything is spent.

Submit and wait

Send the same capability_id and config to POST /generations with max_credits set to the estimate's max_credits_needed. Then wait on the generation_id, or read the batch when the answer carries a batch_group_id. Generations.

Preset submit refusals

The usual submit refusals apply. These are the preset-specific ones:

CauseCodeHTTPRetry
template_id missing on a preset that requires oneinvalid_config400no
template_id is not one of this preset's templatesnot_found404no
The template was withdrawn since you listed itcapability_unavailable404no
The preset needs a higher planrequired_plan403no

On a template refusal, list the templates again and pick another.

Not here

  • No preset authoring. Presets and templates are made by RiffAds.
  • No preview files over the API other than preview_url, which is template art, not your media.
  • No per-template price. Price the full config with POST /estimates.

On this page