Developer Docs

RadiusOS Public API

Workspace-scoped REST API powering the official Zapier integration. Same auth, same endpoints, available for any custom workflow tool you want to wire up.

Base URL: https://www.radiusos.ai

Authentication

Every request is authenticated with a workspace-scoped API key. Keys are created and revoked from inside the workspace, never via the API. A single key authorizes exactly one workspace; if you manage several workspaces, create one key per workspace.

Create an API key

  1. Sign in to RadiusOS and open the workspace you want to expose.
  2. Go to /{org}/{workspace}/settings/api-keys.
  3. Click "Create API key", name it (for example "Zapier - Acme"), and copy the key. The key is shown once.
  4. Paste it into Zapier (or your custom client). Every key looks like ros_<64 hex chars>.

Send the key with every request

Three ways, in priority order:

  • Authorization: Bearer ros_<key> - the canonical header used by the official Zapier integration.
  • X-Api-Key: ros_<key> - convenient for tools whose UI only exposes a single header field.
  • ?api_key=ros_<key> - query-string fallback for quick curl tests. Avoid in production: query strings show up in server logs.

First request

curl https://www.radiusos.ai/api/zapier/auth/test \
  -H "Authorization: Bearer ros_<your_api_key>"

# Response:
# {
#   "org":       { "id": "...", "name": "Acme Roofing", "slug": "acme-roofing" },
#   "workspace": { "id": "...", "name": "Main",         "slug": "main" },
#   "label":     "Acme Roofing / Main"
# }

Rate limits

The API is currently fair-use. A small number of concrete limits live at the plan level rather than as raw per-second caps:

  • Active Zaps per workspace. Free is capped at one active Zap; Pro and above are unlimited. A subscribe call that exceeds the cap returns 402 plan_limit_reached.
  • Contact creation cap. The create-contact action respects the workspace's plan-level contact limit (Free: 250). A create that exceeds the cap returns 402 contact_limit_reached.
  • Abuse protection. Bursty traffic that looks like a misbehaving client may be rate-limited at the edge with a 429. Retry after a few seconds.

If you have a legitimate use case that needs sustained high throughput, write to support@radiusos.ai and we'll raise the ceiling on your workspace.

Errors

Every error response is JSON with a stable shape. Use the error field for machine-readable branching and the message field for user-facing text. Additional fields may be added in the future, never removed.

{
  "error":   "<machine_readable_code>",
  "message": "<human-readable explanation>"
}
StatusError codeMeans
400invalid_json | missing_*Request body or required field missing or malformed. Don't retry without fixing the request.
401missing_api_key | invalid_api_keyAuth header missing or key unrecognized. Don't retry.
402plan_limit_reached | contact_limit_reachedPlan limit hit. Retry will keep failing until the user upgrades or removes data. The body includes plan, limit, and upgradeUrl fields.
404contact_not_foundReferenced resource does not exist in this workspace.
429(none)Edge rate limit. Retry with backoff.
500internal_errorUnexpected server error. The full exception is logged on our side. Safe to retry.

Authentication

GET/api/zapier/auth/test

Test connection

Validates an API key and returns the workspace label. Zapier calls this once when a user connects their account so it can show a human-readable connection name. Useful for any client that wants to verify credentials before issuing real requests.

Response
{
  "org":       { "id": "org_abc", "name": "Acme Roofing", "slug": "acme-roofing" },
  "workspace": { "id": "ws_xyz",  "name": "Main",         "slug": "main" },
  "label":     "Acme Roofing / Main"
}
Errors
StatusCodeWhen
401missing_api_keyNo Authorization header, X-Api-Key header, or ?api_key query parameter present.
401invalid_api_keyThe key is not recognized. Most commonly a typo, a key from a different workspace, or a deleted key.
Example
curl https://www.radiusos.ai/api/zapier/auth/test \
  -H "Authorization: Bearer ros_<your_api_key>"

Triggers (REST hooks)

POST/api/zapier/subscribe

Subscribe to events

Registers a target URL to receive event payloads whenever the specified event fires in the workspace. Used by Zapier to wire a Zap to RadiusOS. The returned id must be passed to the unsubscribe endpoint when the Zap is disabled. Each subscription is signed with its own per-subscription HMAC secret for future signature verification.

Request body
FieldTypeDescription
event*stringOne of: contact.created, contact.updated, contact.stage_changed, task.created, task.completed.
target_url*stringAbsolute http(s) URL that will receive POSTed event payloads.
Response
{
  "id":         "wh_abc123",
  "event":      "contact.created",
  "target_url": "https://hooks.zapier.com/hooks/standard/..."
}
Errors
StatusCodeWhen
400invalid_jsonBody is not valid JSON.
400invalid_eventevent is not one of the supported names.
400invalid_target_urltarget_url is missing or not an http(s) URL.
401missing_api_key | invalid_api_keySee Authentication.
402plan_limit_reachedWorkspace is at its active-Zap cap for the current plan.
Example
curl -X POST https://www.radiusos.ai/api/zapier/subscribe \
  -H "Authorization: Bearer ros_<your_api_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "event": "contact.created",
    "target_url": "https://example.com/inbound"
  }'
DELETE/api/zapier/subscribe/{id}

Unsubscribe from events

Deletes a subscription previously created by the subscribe endpoint. The id is the value returned by subscribe. Idempotent: returns 204 even if the subscription is already gone, so retries are safe. Tenant-scoped: a key from a different workspace cannot delete another workspace's subscription.

Response
(empty body, status 204)
Errors
StatusCodeWhen
401missing_api_key | invalid_api_keySee Authentication.
Example
curl -X DELETE https://www.radiusos.ai/api/zapier/subscribe/wh_abc123 \
  -H "Authorization: Bearer ros_<your_api_key>"
GET/api/zapier/triggers/contacts

Recent contacts (polling fallback + sample data)

Returns the most recent contacts in the workspace, newest first. Zapier uses this as the sample-data source when a user is setting up a Zap and as a polling fallback when REST hooks aren't available. Custom clients can poll this to back-fill events they may have missed.

Query parameters
FieldTypeDescription
limitintegerOptional. Number of contacts to return. Default 5. Min 1, max 25.
Response
[
  {
    "id":         "ctc_abc",
    "name":       "Sarah Chen",
    "email":      "sarah@acme.com",
    "phone":      "+15555550100",
    "stage":      "discovery",
    "created_at": "2026-05-08T14:22:00.000Z",
    ...
  },
  ...
]
Errors
StatusCodeWhen
401missing_api_key | invalid_api_keySee Authentication.
Example
curl 'https://www.radiusos.ai/api/zapier/triggers/contacts?limit=5' \
  -H "Authorization: Bearer ros_<your_api_key>"
GET/api/zapier/triggers/tasks

Recent tasks (polling fallback + sample data)

Returns the most recent tasks in the workspace. Pass ?completed=true to filter to completed tasks ordered by completion time - used by the task-completed Zapier trigger so its sample matches reality.

Query parameters
FieldTypeDescription
limitintegerOptional. Number of tasks to return. Default 5. Min 1, max 25.
completedbooleanOptional. When 'true', returns only completed tasks ordered by completedAt desc.
Response
[
  {
    "id":           "tsk_abc",
    "title":        "Send proposal",
    "contact_id":   "ctc_abc",
    "due_date":     "2026-05-10T00:00:00.000Z",
    "completed_at": null,
    "priority":     "normal",
    ...
  },
  ...
]
Errors
StatusCodeWhen
401missing_api_key | invalid_api_keySee Authentication.
Example
curl 'https://www.radiusos.ai/api/zapier/triggers/tasks?completed=true&limit=5' \
  -H "Authorization: Bearer ros_<your_api_key>"

Actions

POST/api/zapier/actions/create-contact

Create a contact

Creates a contact in the connected workspace. The only required field is name; every other field is optional, matching the in-app contact form. The new contact is placed in the workspace template's first stage unless an explicit stage is supplied.

Request body
FieldTypeDescription
name*stringDisplay name. Trimmed; empty strings are rejected.
emailstringOptional. Validated against a permissive RFC pattern.
phonestringOptional. Stored verbatim; not normalized.
stagestringOptional. Must match a stage key from the workspace template (see /api/zapier/dropdowns/stages). Falls back to the first stage if omitted or invalid.
address_line1stringOptional.
citystringOptional.
statestringOptional.
postal_codestringOptional.
countrystringOptional.
notesstringOptional. Plain text.
Response
{
  "id":      "ctc_abc",
  "name":    "Sarah Chen",
  "email":   "sarah@acme.com",
  "stage":   "discovery",
  "created_at": "2026-05-12T17:00:00.000Z",
  ...
}
Errors
StatusCodeWhen
400invalid_jsonBody is not valid JSON.
400missing_namename is empty after trimming.
400invalid_emailemail is present but does not match a valid email shape.
401missing_api_key | invalid_api_keySee Authentication.
402contact_limit_reachedWorkspace is at its plan's contact cap. Free is capped at 250 contacts.
500internal_errorUnexpected server error. The full exception has been logged. Safe to retry.
Example
curl -X POST https://www.radiusos.ai/api/zapier/actions/create-contact \
  -H "Authorization: Bearer ros_<your_api_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "name":  "Sarah Chen",
    "email": "sarah@acme.com",
    "stage": "discovery"
  }'
POST/api/zapier/actions/create-task

Create a task

Creates a task in the workspace. Optionally linked to a contact via contact_id (the value Zapier's Contact dropdown supplies). due_date accepts any ISO 8601 timestamp the JavaScript Date constructor can parse, so upstream triggers like Calendar events plug in directly.

Request body
FieldTypeDescription
title*stringTask title. Empty strings are rejected.
contact_idstringOptional. Must reference a contact in the same workspace, or the request 404s. Leave empty for an unattached task.
due_datestringOptional. Any string the Date constructor can parse, typically ISO 8601.
prioritystringOptional. One of: low | normal | high | urgent. Defaults to normal.
assigned_tostringOptional. Clerk user id of the workspace member to assign.
notesstringOptional. Plain text.
Response
{
  "id":         "tsk_abc",
  "title":      "Send proposal",
  "contact_id": "ctc_abc",
  "due_date":   "2026-05-15T00:00:00.000Z",
  "priority":   "normal",
  "created_at": "2026-05-12T17:00:00.000Z",
  ...
}
Errors
StatusCodeWhen
400invalid_jsonBody is not valid JSON.
400missing_titletitle is empty after trimming.
401missing_api_key | invalid_api_keySee Authentication.
404contact_not_foundcontact_id was supplied but does not belong to this workspace.
500internal_errorUnexpected server error. The full exception has been logged. Safe to retry.
Example
curl -X POST https://www.radiusos.ai/api/zapier/actions/create-task \
  -H "Authorization: Bearer ros_<your_api_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "title":      "Send proposal",
    "contact_id": "ctc_abc",
    "due_date":   "2026-05-15T00:00:00.000Z",
    "priority":   "high"
  }'
POST/api/zapier/actions/move-stage

Move contact to a new stage

Moves a contact to a different pipeline stage. The stage must match a key in the workspace's template (use /api/zapier/dropdowns/stages to enumerate valid keys). If the contact is already in the target stage the request succeeds and returns the current contact without writing an activity row.

Request body
FieldTypeDescription
contact_id*stringID of the contact to move.
stage*stringStage key from the workspace template.
Response
{
  "id":    "ctc_abc",
  "name":  "Sarah Chen",
  "stage": "won",
  ...
}
Errors
StatusCodeWhen
400invalid_jsonBody is not valid JSON.
400missing_fieldscontact_id or stage missing.
400invalid_stagestage does not exist on this workspace's template.
401missing_api_key | invalid_api_keySee Authentication.
404contact_not_foundcontact_id does not belong to this workspace.
500internal_errorUnexpected server error. The full exception has been logged. Safe to retry.
Example
curl -X POST https://www.radiusos.ai/api/zapier/actions/move-stage \
  -H "Authorization: Bearer ros_<your_api_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_id": "ctc_abc",
    "stage":      "won"
  }'

Dropdowns (helpers)

Versioning

The API is unversioned in the URL today: there is no /v1/ prefix. Backwards-compatible changes (new optional fields, new endpoints, additional error codes) ship continuously without notice. Breaking changes (renaming a field, removing an endpoint, changing required-vs-optional) will be announced at least 60 days in advance to every workspace with active API keys, and a versioned path will be introduced if the change is large enough to need one.

Support

Bugs, edge cases, feature requests, or you just can't make a call work? Email support@radiusos.ai with the request URL, method, body, and response. We typically reply within one business day.

For the official Zapier integration specifically, the easiest path is the Zapier help article.

Built a workflow that works? Share it.

Publish your pipeline template to the RadiusOS marketplace. Free to install, free to publish - help someone in your trade skip the setup.