⚡ rapid.dance

Management API

You can manage everything the query editor handles (create a query, test it, change it, delete it, and mint the key your application will call it with) via the management API so a tool or coding agent can manage queries end to end without a person clicking through the UI. If you are a person, the editor is easier.

Two kinds of key

rq_… call keyCalls queries. This is the one that goes in your application.
rm_… management keyEverything on this page, and it can call queries too. Give it to a tool or an agent. Never ship it inside application code.

Both are created on the API keys page. A management key can mint and revoke call keys, but never other management keys; those are made and revoked by a person.

Requests

GET https://api.rapid.dance/account
Authorization: Bearer rm_…
{"account": {"id": "acc_…", "slug": "demo", "name": "Demo"},
 "key": {"id": "key_…", "name": "agent", "kind": "management", "prefix": "rm_…"},
 "api_base": "https://api.rapid.dance"}

Start with that call: it confirms the key works and tells you the account slug, which is part of every query's endpoint. Request bodies are JSON objects. A member the API does not know is a 400, so a typo cannot pass silently. Replies are JSON.

Authentication here is explicit, unlike the call endpoint, which answers every problem with the same 404: no key, an unknown key or a revoked key is 401; a call key is 403.

The query object

This is what you send when creating or changing a query, and what every read returns.

Member
nameDisplay name. Required.
slugThe last part of the endpoint URL: lowercase letters, digits and hyphens. Derived from the name when omitted. Unique among the account's live queries.
instructionsWhat to do with the input. Required. Say what each output field should contain and what to answer when the input does not allow a confident answer. The input is handed over as data, separately from these instructions.
output_fieldsA list of {name, type, description, default, enum}. Required, at least one. Every field is always present in the answer. The default is what the field holds in the fallback object; without one it is "", 0, false or [].
tierS, M, L, XL. Sets the output size and caps max_time_ms and the input size. Default S.
max_time_msThe end-to-end time budget. When it runs out the caller gets the fallback object. Default 1000, at least 50, at most the tier's bound.
on_failurefallback (default): failures answer 200 with the fallback object and status headers. error: failures answer 502, 503 or 504.
log_inputWhether request inputs are kept in the logs. Default true.
enabledA disabled query answers with the fallback object (or 503 in error mode). Default true.
sample_inputA JSON object shown in the editor and used by test runs. null clears it.

Read-only members in every reply: id (qry_…), version (goes up on every change; the editor keeps each version), endpoint (the absolute URL to call), fallback (the object callers get when the query cannot answer), created_at and updated_at.

Field types

string, number, integer, booleanPlain values.
enumOne of the strings listed in enum. Needs a default from that list.
string[], number[]Flat lists.

Nested objects are not supported. Keep fields few and flat; small answers come back faster and are easier to get right.

Create a query

curl -X POST https://api.rapid.dance/queries \
  -H 'Authorization: Bearer rm_…' -H 'Content-Type: application/json' \
  -d '{
    "name": "Repo selector",
    "slug": "repo-selector",
    "instructions": "Given the user'\''s repos and the name they chose for a deployment, pick the repo the deployment most likely belongs to. If none is a plausible match, leave selected_repo empty.",
    "output_fields": [
      {"name": "selected_repo", "type": "string", "description": "Full repo name, or empty if unsure"}
    ],
    "tier": "S",
    "max_time_ms": 1000,
    "sample_input": {"repos": ["myexample/myblog", "myexample/waitlist-api"], "deployment_name": "blog"}
  }'
HTTP/2 201 Created

{"id": "qry_…", "slug": "repo-selector", "name": "Repo selector", "instructions": "…",
 "output_fields": [{"name": "selected_repo", "type": "string", "description": "Full repo name, or empty if unsure"}],
 "tier": "S", "max_time_ms": 1000, "on_failure": "fallback", "log_input": true, "enabled": true,
 "sample_input": {"repos": ["myexample/myblog", "myexample/waitlist-api"], "deployment_name": "blog"},
 "version": 1, "endpoint": "https://api.rapid.dance/demo/repo-selector", "fallback": {"selected_repo": ""},
 "created_at": "…", "updated_at": "…"}

A slug that is already in use is a 409. A definition with problems is a 400 whose error.details lists each one in plain words.

Test it

curl -X POST https://api.rapid.dance/queries/repo-selector/test \
  -H 'Authorization: Bearer rm_…' -H 'Content-Type: application/json' \
  -d '{"input": {"repos": ["myexample/myblog", "myexample/waitlist-api"], "deployment_name": "blog"}}'
{"request_id": "req_…", "status": "ok", "http_status": 200, "fallback": false,
 "output": {"selected_repo": "myexample/myblog"},
 "reasoning": "…why the model chose that…",
 "latency_ms": 412, "version": 1}

A test run is a real call: it is billed like one and appears in the logs, but it runs even when the query is disabled and it does not count toward the account's daily cap. The reasoning text is the useful part when an answer is wrong: read it, change the instructions, run the same input again. Try three to five realistic inputs, including one that should produce the fallback, before you call the query done. status is ok, empty (the model answered with exactly the fallback values), or a failure kind; when it is timeout, compare latency_ms with max_time_ms and raise the budget or shorten the output.

The input you test with is saved as the query's sample input.

Change it

PATCH changes only the members you send. PUT replaces the whole definition: anything you leave out goes back to its default, so send the complete object.

curl -X PATCH https://api.rapid.dance/queries/repo-selector \
  -H 'Authorization: Bearer rm_…' -H 'Content-Type: application/json' \
  -d '{"instructions": "…the improved instructions…"}'

Either way the reply is the full query with version increased by one. Queries can be addressed by slug or by id.

Read and list

GET https://api.rapid.dance/queries                 # {"queries": [...]}
GET https://api.rapid.dance/queries/repo-selector   # one, by slug or by id

Delete

DELETE https://api.rapid.dance/queries/repo-selector     # 204

From then on calls answer 404 and the query is gone as far as the API is concerned: reading, changing or testing it is a 404 too. Its logs are kept, and a person can restore it in the editor.

Call keys

POST https://api.rapid.dance/keys        {"name": "production"}
→ 201 {"id": "key_…", "name": "production", "kind": "call", "prefix": "rq_…", "key": "rq_…full key…", …}

GET  https://api.rapid.dance/keys        {"keys": [{"id", "name", "kind", "prefix", "created_at", "last_used_at", "revoked_at"}]}
DELETE https://api.rapid.dance/keys/key_…   # 204; revoking a management key here is 403

The full key appears once, in the create reply. Put it where your application reads secrets from, never in source.

Errors

400 bad_requestBody is not a JSON object, has an unknown member, or the test input is not an object.
400 validation_failedThe definition has problems; error.details lists them.
401 unauthorizedNo key, unknown key, or revoked key.
403 forbiddenA call key was used, or you tried to revoke a management key.
404 not_foundNo such query or key in this account.
405 method_not_allowedWrong verb; the Allow header lists the right ones.
409 conflictSlug already in use.
413 too_largeBody over 256 KB, or a test input over the tier's limit.
429 rate_limitedToo many requests for this key.

Error bodies look like {"error": {"code": "…", "message": "…", "details": ["…"]}}.

For coding agents

https://rapid.dev/llms.txt explains all of this in one plain-text file written for a model: what rapid.dance is, how to create and refine a query, and how to put the call into an application. A Claude Code skill that fetches it and walks through the whole job is at https://rapid.dev/skill.md:

mkdir -p ~/.claude/skills/rapid-dance && curl -fsSL https://rapid.dev/skill.md -o ~/.claude/skills/rapid-dance/SKILL.md

Then, in Claude Code: “Use rapid.dance to add a feature that …”. The agent will ask for a management key; make one on the API keys page.