HCC Docs

Call webhooks

When a call reaches one of your numbers, HCC POSTs a signed request to the number's call webhook URL. Reply with Call Instructions. Hono on Cloudflare Workers:

import { Hono } from 'hono';
import { SIGNATURE_HEADER, instructions as i, respond, webhooks } from '@hcc/sdk';

type Env = { HCC_CALL_WEBHOOK_SECRET: string };
const app = new Hono<{ Bindings: Env }>();

app.post('/hcc/call', async (c) => {
  const body = await c.req.text(); // raw body: needed for the signature
  const ok = await webhooks.verify({
    secret: c.env.HCC_CALL_WEBHOOK_SECRET,
    body,
    signature: c.req.header(SIGNATURE_HEADER),
  });
  if (!ok) return c.text('invalid signature', 401);

  return respond(
    i.say('Thanks for calling Acme.'),
    i.gather({ input: ['dtmf'], numDigits: 1, prompt: i.say('Press 1 for sales.'), tag: 'menu' }),
    i.connectAgent('agt_123'),
  );
});

export default app;

respond(...) returns a JSON Response with { instructions }; use instructionsBody(...) if your framework wants the plain object. Builders validate their input and throw on invalid values (empty text, non-E.164 numbers, out-of-range timeouts).

Available builders: say, play, pause, connectAgent, dial, enqueue, gather, record, hangup.

What a caller enters on a gather shows on the call's timeline and in its API record. For card numbers, PINs and the like, pass sensitive: true: your flow or webhook still gets the input, and we keep only how much was entered ("4 digits entered"). A webhook delivery of a sensitive gather can't be resent, because its event isn't kept. Anything your own handler stores or logs is yours to protect.