Now inviting stores. Join the waitlist to hear the agent call you.

Join the waitlist

Search the docs

Find a docs page

API reference

Webhooks

Preview

Receive signed events as calls progress, check the signature, answer fast, and handle retries, duplicates and order safely.

RowCall sends a signed POST to your endpoint each time something happens on a run. Add endpoints in Developers → Webhooks, for live or test events, and choose which event types each one receives. URLs must be HTTPS. Runs started from the RowCall app announce events too, so your systems hear about every call.

POST /v1/runs, then the run goes scheduled → dialing → done, and run.completed reaches your webhook.

The events

EventWhen
run.queuedA run was made and is waiting to be placed
run.ringingAn attempt is ringing
run.answeredThe shopper picked up
run.no_answerAn attempt went unanswered (sent for every one, retry or not)
run.completedAn answered call ended: the run carries its outcome and answers
run.failedThe run gave up: no attempt reached the shopper, or it couldn't be placed
run.canceledThe run was cancelled, or the shopper opted out before the next attempt
action.completedAn action succeeded
action.failedAn action was refused, timed out or isn't connected
handoff.requestedA person was asked for on the call
handoff.connectedA person took the call
optout.receivedThe shopper asked not to be called again
pingOnly from Send a test event, to check your endpoint

Apps connected over OAuth also always get app.installed and app.uninstalled. See Build an integration.

What an event carries

Every event has the same envelope: its id, type, mode (live or test), the orgId it's about, createdAt, and data. Run events carry data.run as GET /v1/runs/{runId} shows it at that moment, including your metadata, so you rarely need to read the run again. Events about one call also carry data.callId, plus the action, the handoff or the opted-out phone. Each event's exact body and an example are in the reference.

Headers and signature

Each request carries three headers:

RowCall-Signature: t=1760348000,v1=5f2b…
RowCall-Event-Id: evt_c8v6b4n2m0l8k6j4h2g0
RowCall-Event-Type: run.completed

v1 is an HMAC-SHA256, in hex, of t + . + the raw request body, keyed with your endpoint's signing secret (whsec_…, shown once when you add the endpoint or roll its secret). After you roll a secret, the old one keeps signing for 24 hours, so the header carries two v1 values; accept the request when any of them matches.

Check the signature before you parse the body, reject a t more than 5 minutes from now, and compare in constant time. The SDK does all three:

import { verifyWebhook } from '@rowcall/sdk'
import express from 'express'

const app = express()

// The raw body, not parsed JSON: the signature covers the exact bytes RowCall sent.
app.post('/rowcall/events', express.raw({ type: 'application/json' }), async (req, res) => {
  const body = req.body.toString()
  const isGenuine = verifyWebhook({
    body,
    signature: req.get('RowCall-Signature') ?? '',
    secret: process.env.ROWCALL_SIGNING_SECRET,
  })
  if (!isGenuine) return res.sendStatus(401)
  res.sendStatus(200)
  await handleEvent(JSON.parse(body)) // after answering
})

The reference has the same check in Python.

Answer fast, work later

Reply with any 2xx within 10 seconds, then do the work, on a queue if it can take a while. Anything else counts as a failure: another status, no reply in time, or a redirect (redirects are not followed).

Retries, duplicates and order

  • Retries. A failed delivery is retried after 1 minute, 5 minutes, 30 minutes, 2 hours, 6 hours and 12 hours, then marked failed. When a live endpoint gives up, your org's developers are told.
  • Duplicates. Delivery is at least once: the same event can arrive more than once. Store the event ids you've handled and skip repeats. See Idempotency.
  • Order. Events can arrive out of order, especially after a retry. Use createdAt and the run's own status, and read the run with GET /v1/runs/{runId} when order matters.

Delivery log and test events

Each endpoint in Developers → Webhooks has a delivery log: every event, how its last try went, and its body. You can send any delivery again, for example after fixing a bug in your handler. Send a test event sends a ping, so you can check your signature code before any run.

Next stepActions

Let a call change things in your systems.