Skip to content
Remute

The Remute API and webhooks

Read your calls, contacts and appointments, check availability and get a signed event the moment something happens. Included in Pro and Business.

OpenAPI description (JSON)

Overview

The base URL is https://remuteai.com/api/v1. Requests and responses are JSON. Every query is limited to the workspace the key belongs to.

The API is available on the Pro and Business plans. With a key from a Free workspace you get a 403 plan_required error.

Example request
curl "https://remuteai.com/api/v1/calls?limit=5" \
  -H "Authorization: Bearer rk_live_YOUR_KEY"
Example response
{
  "data": [
    {
      "id": "a90c…",
      "started_at": "2026-10-26T09:12:40+00:00",
      "duration_seconds": 142,
      "from_number": "+34600000000",
      "language": "es",
      "outcome": "booked",
      "summary": "…",
      "contact_id": "41b7…",
      "agent_id": "9b54…"
    }
  ],
  "has_more": true,
  "next_cursor": "MjAyNi0x…"
}

API keys

Create keys in the app under Configure, Developers (owners and admins). A key looks like rk_live_ followed by 32 letters and digits, and is shown once when you create it. We store only its SHA-256 hash, so we cannot show it again: if you lose it, revoke it and create another.

Send it in the Authorization header: Authorization: Bearer rk_live_… . There are two permission levels.

  • read: read-only access to every GET endpoint.
  • read_write: the same, plus creating and editing contacts and appointments and managing webhook endpoints.

A missing, malformed, unknown or revoked key returns 401 unauthorized; a read key on a write call, 403 insufficient_scope.

Endpoints

EndpointWhat it does
GET /meThe key, its permissions and its workspace.
GET /callsList calls, newest first.
GET /calls/{id}One call with transcript, recording URL and the data collected.
GET /contacts, GET /contacts/{id}Contacts.
GET /appointments, GET /appointments/{id}Appointments. The list accepts from and to (ISO 8601) to filter by start time.
GET /availabilityFree slots for the next 14 days, calculated like the assistant does. Optional date=YYYY-MM-DD.
POST /contacts, PATCH /contacts/{id}Create a contact (phone in E.164; an existing phone updates that contact) or edit name, email, language and notes (read_write key).
POST /appointments, PATCH /appointments/{id}Book an appointment, or reschedule, cancel or edit one (read_write key). Answers 409 slot_taken if the time overlaps another appointment.
GET /webhooks, GET /webhooks/{id}Your webhook endpoints.
POST /webhooksCreate an endpoint (read_write key). Returns the signing secret once.
DELETE /webhooks/{id}Delete an endpoint (read_write key).

Every write is recorded in your workspace audit log. Changes made through the API also fire the matching webhook events (appointment.booked, appointment.changed, appointment.cancelled, contact.created).

Pagination, limits and errors

  • Lists (calls, contacts, appointments) are newest first. Use limit (1 to 100, default 25) and pass the next_cursor value as cursor to get the next page. The cursor is opaque. When has_more is false there are no more pages.
  • Rate limit: 60 requests per minute per key. Over the limit you get 429 rate_limited with a Retry-After header of 60 seconds.
  • Errors have the shape {"error": {"code": "…", "message": "…"}}. Codes you may see: unauthorized (401), plan_required and insufficient_scope (403), not_found (404), method_not_allowed (405), invalid_request (400), limit_reached (409), rate_limited (429), internal_error (500), unavailable (503).
  • A workspace can have up to 10 webhook endpoints.

Webhooks

Add an endpoint in the app (Configure, Developers) or with POST /webhooks. Choose the events you want or use * for all. We send each event to your URL as a POST with a JSON body, and your server answers with any 2xx status to acknowledge it.

EventWhen
call.completedA call has been saved. Includes the summary and outcome; the transcript is not included (fetch the call by id).
appointment.bookedA new appointment.
appointment.changedStart time, end time or status changed.
appointment.cancelledAn appointment was cancelled.
contact.createdA new contact.
Event body (appointment.booked)
{
  "id": "6f1c0a52-3b7e-4c1e-9a55-0d2c7b1d9e11",
  "type": "appointment.booked",
  "created_at": "2026-10-26T09:14:03.120Z",
  "workspace_id": "c2a4…",
  "data": {
    "id": "8d3e…",
    "starts_at": "2026-10-28T09:00:00+00:00",
    "ends_at": "2026-10-28T09:30:00+00:00",
    "status": "scheduled",
    "contact_id": "41b7…",
    "call_id": "a90c…",
    "notes": null,
    "created_at": "2026-10-26T09:14:03.100+00:00"
  }
}
Create an endpoint through the API
curl -X POST https://remuteai.com/api/v1/webhooks \
  -H "Authorization: Bearer rk_live_YOUR_READ_WRITE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/remute-hook","events":["call.completed","appointment.booked"]}'

The id of the event is the same as the webhook-id header. Delivery is at least once, so use the id to ignore duplicates.

Verifying the signature

Every request carries the three Standard Webhooks headers (the scheme Svix uses), so any Svix or standardwebhooks library verifies it.

  • webhook-id: the event id.
  • webhook-timestamp: Unix time in seconds when the attempt was signed.
  • webhook-signature: v1, followed by a comma and the base64 of an HMAC-SHA256. It is computed over id.timestamp.body (the three joined with dots) using as key the base64-decoded part of your whsec_ secret.

Use the raw body, exactly as received: parsing and re-serialising the JSON changes the bytes. Compare in constant time and reject timestamps too far from now (we suggest 5 minutes) to stop replays. Each retry is signed again with a fresh timestamp.

Verification in Node.js
import { createHmac, timingSafeEqual } from "node:crypto";

// rawBody: the request body exactly as received (a string, not re-serialised JSON)
export function verify(rawBody, headers, secret) {
  const id = headers["webhook-id"];
  const ts = headers["webhook-timestamp"];
  const sigs = headers["webhook-signature"];
  if (!id || !ts || !sigs) return false;
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false; // replay window: 5 min

  const key = Buffer.from(secret.replace(/^whsec_/, ""), "base64");
  const expected = createHmac("sha256", key).update(`${id}.${ts}.${rawBody}`).digest();

  return sigs.split(" ").some((entry) => {
    const [version, sig] = entry.split(",");
    if (version !== "v1" || !sig) return false;
    const given = Buffer.from(sig, "base64");
    return given.length === expected.length && timingSafeEqual(given, expected);
  });
}

The signing secret is returned once when you create the endpoint through the API, and owners and admins can also see it in the app.

Retries and limits of delivery

  • We wait up to 8 seconds for an answer. A timeout, a network error or any status outside 2xx counts as a failure. Redirects are not followed.
  • After a failed attempt we retry after 1 minute, 5 minutes, 30 minutes, 2 hours and 12 hours (six attempts in total). After that the delivery is marked as failed.
  • If 10 deliveries in a row run out of attempts, the endpoint is switched off (you will see “Disabled after repeated failures” in the app).
  • Only https URLs are accepted, on the default port, without credentials. localhost, private and link-local addresses (10.x, 192.168.x, 127.x, 169.254.x and so on) and names ending in .local or .internal are rejected, when you register the endpoint and again on every send.

Honest limits of today. A scheduled job looks for due retries every minute, so a retry can arrive up to about a minute after its time. We check the address as written: a public domain name that points to a private IP is not detected, because our servers do not resolve DNS before sending. Do not rely on webhooks for anything that cannot tolerate a delay.

Calendar feed (.ics)

In Configure, Developers you can create a private calendar address. Paste it in Google Calendar (Other calendars, From URL), Outlook or Apple Calendar to see your Remute appointments there.

  • It is one-way: changes made in your calendar do not come back to Remute.
  • It includes appointments from the last 30 days and everything ahead, up to 2,000.
  • Calendar apps refresh it every few hours, not instantly.
  • Anyone with the address can read the feed, so treat it like a password. It is limited to 60 requests per hour.

Questions

Does it work with Zapier, Make or n8n?

Yes, through their generic webhook and HTTP steps: point a webhook endpoint at the URL they give you, or poll the API with a key. There is no dedicated app in their catalogues yet.

Can I create appointments or contacts through the API?

Not yet. Today the API reads calls, contacts and appointments and manages webhook endpoints.

Which plans include the API?

Pro and Business. Free workspaces get a 403 plan_required error.

Is there a sandbox or test mode?

No. Keys are live keys on your own workspace data.

Build on top of your phone line.

Create a free account to explore the app, then upgrade to Pro to get a key.

Create a free account
Start free