Relayna logo Relayna
Integration Guide

Integration Guide

Add human-in-the-loop checkpoints to your AI agent or automation in minutes. Authenticate, create a checkpoint, share the review link, and receive the decision via webhook.

API Reference

Interactive Explorer

Browse all endpoints, try requests live, and inspect response schemas with the Swagger UI.

Open Swagger UI

OpenAPI JSON Spec

AI-ready

Feed this URL directly into ChatGPT, Claude, Cursor, or Copilot to generate type-safe clients and boilerplate instantly.

Quick Start

Get your first checkpoint live in three steps:

  1. 1 Sign up and generate an API key in Dashboard → API Keys
  2. 2 POST to /api/checkpoints with a title, instructions, and optional callback_url
  3. 3 Share the returned review_link with a human — they click Approve or Reject and your webhook fires
curl — minimal example
curl -X POST https://relayna.app/api/checkpoints \
  -H "Authorization: Bearer $RELAYNA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Approve deployment to production",
    "instructions": "Review the diff and confirm it is safe to deploy.",
    "callback_url": "https://yourapp.com/webhooks/relayna"
  }'

# Response
{
  "checkpoint": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "public_id": "aB3xYz7qRstUvW",
    "status": "pending",
    "title": "Approve deployment to production",
    "ttl_seconds": null,
    "expires_at": null,
    "inserted_at": "2026-04-01T10:00:00.000000Z"
  },
  "review_url": "https://relayna.app/r/k3Hq9mXzP2...",
  "link": { "id": "...", "status": "active", "ttl_seconds": 604800, "expires_at": "2026-04-08T10:00:00.000000Z" }
}

API Console

Build and test real API requests with live preview, pre-filled mock data, and response inspection — no terminal needed.

Open API Console
API Console — build and send live requests with mock data
Pre-filled mock payloads for every endpoint
Live curl, Python & JavaScript code preview
Instant response inspection in-browser

Authentication

Bearer Token (API Key)

All API requests must include your API key as a bearer token in the Authorization header. Create and manage keys in Dashboard → API Keys.

Authorization: Bearer YOUR_RELAYNA_API_KEY
Content-Type: application/json
Note: Reviewers accessing a checkpoint via a magic link do not need an account or API key. The link token is the credential.

Create Checkpoint

POST /api/checkpoints

Creates a new review checkpoint and returns a magic review link. Optionally attach files, text snippets, JSON data, or external URLs as review items.

Request body

title string required

Short summary shown to the reviewer as the checkpoint title.

instructions string

Detailed instructions or context for the reviewer. Rendered as a highlighted callout on the review page.

summary string

Optional one-line summary or context shown below the title.

callback_url string

HTTPS URL that receives a POST with the decision the moment the reviewer acts. Retried up to 3 times on failure.

callback_headers object

Extra headers sent with every webhook POST to callback_url (e.g. {"Authorization": "Bearer secret"}).

ttl_seconds integer

Seconds until the checkpoint auto-expires. After this time the checkpoint transitions to expired and the review link stops working.

external_ref string

Your own identifier (e.g. a job ID or order number). Echoed back in the webhook payload.

metadata object

Arbitrary key/value pairs stored with the checkpoint and included in the webhook payload.

submitted_by string

Free-form label identifying the agent or system that created this checkpoint (e.g. "n8n-workflow").

items array

List of items to attach for the reviewer to examine. See item types below.

Item types

Each item in the items array must include an item_type and optional label.

"asset" — asset_id: string

A previously uploaded file. The reviewer sees the filename and a download button.

"text" — content_text: string

Inline text block displayed directly on the review page.

"json" — content_json: object

JSON data rendered as syntax-highlighted code.

"link" — content_text: string (URL)

An external URL shown as a clickable link. Pass the URL in content_text.

Upload Files

Files upload directly to Cloudflare R2 — Relayna is never in the data path. There are two upload methods:

POST /api/assets/upload multipart/form-data

Simple server-side upload. Send the file as a multipart form field named file.

curl -X POST https://relayna.app/api/assets/upload \
  -H "Authorization: Bearer $RELAYNA_API_KEY" \
  -F "[email protected]" \
  -F "purpose=invoice" \
  -F "ttl_seconds=604800"

# Returns
{
  "asset": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "filename": "invoice.pdf",
    "content_type": "application/pdf",
    "byte_size": 142336,
    "status": "uploaded",
    "purpose": "invoice",
    "ttl_seconds": 604800,
    "expires_at": "2026-04-08T10:00:00.000000Z",
    "uploaded_at": "2026-04-01T10:00:00.000000Z",
    "inserted_at": "2026-04-01T10:00:00.000000Z"
  },
  "access_url": "https://r2.example.com/...",
  "access_url_expires_at": "2026-04-08T10:00:00.000000Z"
}

Presigned PUT (direct browser upload)

For large files or client-side uploads, request a presigned PUT URL. The file goes directly to R2; only the asset ID is stored in Relayna.

  1. 1. POST /api/assets/upload with {"presigned": true, "filename": "invoice.pdf", "content_type": "application/pdf"} — returns upload_url and asset_id
  2. 2. PUT the file bytes directly to upload_url
  3. 3. Use the asset_id in your checkpoint's items array
POST /api/assets/:id/download-request

Generates a short-lived presigned GET URL for an uploaded asset. Use this to give reviewers or downstream services temporary access to a file without exposing permanent storage credentials.

{
  "download_url": "https://r2.example.com/...",
  "expires_in_seconds": 3600,
  "asset": { "id": "...", "filename": "invoice.pdf", "status": "uploaded", ... }
}

Checkpoint Schema

GET /api/checkpoints/:id

Returns the full checkpoint including all attached items. Asset items include a short-lived presigned access_url.

Checkpoint object
{
  "id": "550e8400-e29b-41d4-a716-446655440000",  // UUID
  "public_id": "aB3xYz7qRstUvW",                 // short URL-safe ID
  "status": "pending",              // pending | approved | rejected | needs_changes | expired | cancelled
  "title": "Approve deployment",
  "instructions": "...",
  "summary": null,                  // optional one-line context
  "review_type": "ad_hoc",
  "callback_url": "https://yourapp.com/webhooks/relayna",
  "ttl_seconds": 604800,
  "expires_at": "2026-04-08T10:00:00.000000Z",   // null if no TTL
  "external_ref": "job_abc123",
  "metadata": { "env": "production" },
  "submitted_by": "my-agent",       // null if not set
  "decided_at": null,               // ISO 8601, set when reviewer acts
  "decision_comment": null,         // reviewer's comment
  "inserted_at": "2026-04-01T10:00:00.000000Z",
  "items": [
    {
      "id": "550e8400-...",
      "item_type": "asset",         // asset | text | json | link
      "label": "Invoice PDF",
      "asset_id": "550e8400-...",
      "content_text": null,
      "content_json": null,
      "position": 0,
      "access_url": "https://r2.example.com/...",           // asset items only
      "access_url_expires_at": "2026-04-08T10:00:00.000000Z"
    }
  ]
}

Status state machine

pending approved or rejected or needs_changes or expired or cancelled
POST /api/checkpoints/:id/cancel

Cancels a pending checkpoint (e.g. the workflow was aborted). Only pending checkpoints can be cancelled. Returns the updated checkpoint object.

curl -X POST https://relayna.app/api/checkpoints/$CHECKPOINT_ID/cancel \
  -H "Authorization: Bearer $RELAYNA_API_KEY"
POST /api/review-links/:id/revoke

Revokes a review link so it can no longer be used. The checkpoint itself remains accessible via the API. Returns the updated link status.

{ "link": { "id": "...", "status": "revoked" } }

Webhook Payload

When a reviewer acts, Relayna immediately POSTs this payload to your callback_url. Retried up to 3 times with exponential backoff on non-2xx responses.

POST your_callback_url
{
  "checkpoint_id": "550e8400-e29b-41d4-a716-446655440000",
  "public_id": "aB3xYz7qRstUvW",
  "status": "approved",             // approved | rejected | needs_changes | expired | cancelled
  "decision": "approve",            // "approve" | "reject" | "needs_changes" | null (null when expired/cancelled)
  "comment": "Looks good, vendor details match.",
  "decided_at": "2026-04-01T14:32:00.000000Z",
  "external_ref": "job_abc123",     // echoed from checkpoint creation
  "metadata": { "env": "production" }
}
Tip: Use external_ref to correlate the webhook with your internal job or workflow ID — no database lookup needed.

Poll Status

If you cannot receive webhooks, poll the lightweight status endpoint instead.

GET /api/checkpoints/:id/status
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "public_id": "aB3xYz7qRstUvW",
  "status": "approved",
  "decided_at": "2026-04-01T14:32:00.000000Z",
  "decision_comment": "Looks good.",
  "external_ref": "job_abc123"
}
Poll at a reasonable interval (e.g. every 5–10 seconds). Use webhooks whenever possible — they are instant and do not require polling logic.

Code Examples

curl -X POST https://relayna.app/api/checkpoints \
  -H "Authorization: Bearer $RELAYNA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Approve deployment to production",
    "instructions": "Review the diff and confirm it is safe to deploy.",
    "callback_url": "https://yourapp.com/webhooks/relayna",
    "external_ref": "deploy_20251119",
    "items": [
      {
        "item_type": "text",
        "label": "Diff summary",
        "content": "3 files changed, 42 insertions, 5 deletions"
      }
    ]
  }'

Best Practices

🔗

Use webhooks over polling

Webhooks are instant and stateless. Only poll if you cannot expose a public endpoint (e.g. local dev).

🏷️

Set external_ref

Pass your internal job or order ID as external_ref. It's echoed in the webhook so you never need a reverse lookup.

⏱️

Set ttl_seconds

Always set a sensible TTL so stale checkpoints don't linger. Checkpoints auto-expire after the TTL; poll /status or use webhooks to detect expiry.

📎

Attach context

The more context reviewers have (files, inline data, clear instructions) the faster and more accurate their decision.

🔑

Scope API keys

Create one API key per agent or service. If a key is compromised, rotate only that key without affecting others.

🔄

Handle all statuses

Your callback_url fires on approved, rejected, and needs_changes. Poll /status to detect expired or cancelled states. Handle all outcomes, not just approved.