Skip to content
Vocenya

Build on Vocenya

Pull calls, leads, bookings and chats into your own systems, send leads in for a fast AI callback, and get a signed webhook the moment something happens. AI assistants can work with your account through our MCP server.

  • REST API

    JSON over HTTPS at /api/public/v1, described by an OpenAPI document you can generate a client from.

  • Webhooks

    Leads, calls, bookings, chat handoffs and outbound calls, signed with HMAC-SHA256 and retried when your server is down.

  • MCP servers

    Connect Claude, Cursor or any MCP client to your account, or to public facts about Vocenya.

Quickstart

Create a key in the app under Developers, then send it as a Bearer token. Every request goes to https://vocenya.com/api/public/v1.

Create a lead
curl -X POST https://vocenya.com/api/public/v1/leads \
  -H "Authorization: Bearer $VOCENYA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "name": "Maria Lopez",
    "phone_number": "+12015550147",
    "email": "maria@example.com",
    "reason": "Quote for a water heater replacement"
  }'
List recent calls
curl https://vocenya.com/api/public/v1/calls \
  -H "Authorization: Bearer $VOCENYA_API_KEY" \
  -H "Accept: application/json"

Lists come back newest first, a page at a time. Pass the page's meta.next_cursor as ?cursor= to get the next. Asking for an AI callback when you create a lead also needs the outbound:write scope. Errors always have the same shape: {"message": "...", "code": "..."}, with errors added when a field fails validation.

Authentication

API keys belong to your organization, not to a person, so they keep working when someone leaves the team. The full key is shown once, when you create it; we keep only a hash. Give each key only the scopes it needs, and revoke it in the app at any time.

ScopeAllows
calls:readRead calls
leads:readRead leads
leads:writeCreate leads
bookings:readRead bookings
outbound:readRead outbound AI calls
outbound:writeQueue outbound AI calls and check their status
dnc:readRead the Do Not Call list
dnc:writeAdd to and remove from the Do Not Call list
chats:readRead website chats
chats:writeReply to and close website chats
webhooks:manageManage webhooks

A missing or revoked key gets 401. A key without the scope a request needs gets 403 with the code missing_scope.

Webhooks

Add an https endpoint in the app, or with the API, and pick the events it should receive. We POST JSON to it when:

  • lead.createdA lead was captured
  • call.completedAn inbound call ended
  • booking.createdAn appointment was booked
  • chat.handed_offA website chat was handed to a person
  • outbound_call.completedAn outbound call ended
  • chat.startedA visitor started a website chat
  • chat.message.createdA website chat got a new message
  • chat.lead_capturedA website chat captured a lead
  • chat.handoff_requestedThe visitor or the AI asked for a person in a website chat
  • chat.closedA website chat was closed
  • call.missedA caller hung up before anyone answered
  • message.takenA live agent took a message from a caller
  • sms.receivedA customer texted one of your numbers
  • sms.sentA text was sent from one of your numbers

Each delivery carries a Vocenya-Signature header in the form t=timestamp,v1=hex. The signature is an HMAC-SHA256 of timestamp.raw_body using your endpoint secret. Check it against the raw request body, before parsing, and reject anything older than 5 minutes.

Verify a signature in PHP
<?php

$secret = getenv('VOCENYA_WEBHOOK_SECRET');
$payload = file_get_contents('php://input');
$header = $_SERVER['HTTP_VOCENYA_SIGNATURE'] ?? '';

parse_str(str_replace(',', '&', $header), $parts);
$timestamp = (int) ($parts['t'] ?? 0);
$signature = (string) ($parts['v1'] ?? '');

$expected = hash_hmac('sha256', $timestamp.'.'.$payload, $secret);

if (! hash_equals($expected, $signature) || abs(time() - $timestamp) > 300) {
    http_response_code(400);
    exit;
}

$event = json_decode($payload, true);
http_response_code(200);
Verify a signature in Node.js
import crypto from 'node:crypto';

// rawBody must be the exact bytes received, before JSON parsing.
export function verifyVocenyaSignature(rawBody, header, secret) {
  const parts = Object.fromEntries(
    header.split(',').map((part) => part.split('=')),
  );
  const timestamp = Number(parts.t);
  const expected = crypto
    .createHmac('sha256', secret)
    .update(`${timestamp}.${rawBody}`)
    .digest('hex');

  const fresh = Math.abs(Date.now() / 1000 - timestamp) <= 300;
  const a = Buffer.from(expected);
  const b = Buffer.from(parts.v1 ?? '');

  return fresh && a.length === b.length && crypto.timingSafeEqual(a, b);
}

Answer with any 2xx within 10 seconds. If your server errors, times out or is unreachable, we retry with exponential backoff, from one minute up to several hours apart, for up to 8 attempts. Each event has a unique id, in the body's id and the Vocenya-Delivery header, so you can safely ignore one you have already handled.

A key that adds endpoints through the API needs webhooks:manage plus the read scope of each event it subscribes to, for example leads:read for lead.created.

Website live chat

The chat is one script tag with the business's public site key, loaded once on every page, just before </body>. Don't bundle, self-host or proxy the script.

Add the chat
<script src="https://vocenya.com/api/chat/widget.js" data-key="pk_YOUR_SITE_KEY" async></script>

Building the site with an AI tool like Lovable, Bolt, v0, Replit, Cursor or Claude Code? Point it at the chat install instructions: where the tag goes in Next.js, Vite, Nuxt, SvelteKit, Astro, Remix and the site builders, the Content Security Policy sources to add, and the JavaScript API (Vocenya('open'), Vocenya('identify', {...})). In the app, each business also gets a ready-to-paste prompt with its own key.

MCP servers

The Model Context Protocol (MCP) is an open standard that lets AI assistants call tools on other services. Vocenya runs two MCP servers over streamable HTTP.

Platform server

https://vocenya.com/mcp/platform

Your own calls, leads, bookings, chats and Do Not Call list, plus queuing outbound calls with the usual consent and calling-hours checks. Needs an API key; each tool checks the key's scopes.

Site server

https://vocenya.com/mcp/site

Public and read-only: pricing, industries, services, locations and our guides. No key needed, so an assistant can answer questions about Vocenya accurately.

Claude Code
# Your account (needs an API key)
claude mcp add --transport http vocenya https://vocenya.com/mcp/platform \
  --header "Authorization: Bearer vk_live_..."

# Public site facts (no key)
claude mcp add --transport http vocenya-site https://vocenya.com/mcp/site
Claude Desktop (claude_desktop_config.json)
{
  "mcpServers": {
    "vocenya": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://vocenya.com/mcp/platform",
        "--header",
        "Authorization:${VOCENYA_AUTH}"
      ],
      "env": {
        "VOCENYA_AUTH": "Bearer vk_live_..."
      }
    },
    "vocenya-site": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://vocenya.com/mcp/site"
      ]
    }
  }
}
Cursor (.cursor/mcp.json)
{
  "mcpServers": {
    "vocenya": {
      "url": "https://vocenya.com/mcp/platform",
      "headers": {
        "Authorization": "Bearer vk_live_..."
      }
    },
    "vocenya-site": {
      "url": "https://vocenya.com/mcp/site"
    }
  }
}

Replace vk_live_... with your key. Treat it like a password: anyone with it can use the scopes it carries.

Rate limits

Each API key can make 120 requests a minute by default, shared between the REST API and the platform MCP server. Over the limit you get 429 Too Many Requests with a Retry-After header. The public site server, and repeated requests with a missing or invalid key, are limited per IP address.

HIPAA mode

For practices in HIPAA mode, the API and the MCP server leave out call transcripts, summaries, handoff notes, chat message text and the reason and details of a lead. Webhooks carry ids only, so your server fetches details over an authenticated request. Call recordings are never available through the API.

Questions

Who owns an API key?

Your business does. Keys belong to your Vocenya organization, not to the person who created them, so they keep working when a teammate leaves. An account owner creates and revokes keys in the app, under Developers.

Can I see an API key again after I create it?

No. The full key is shown once, when you create it. Vocenya stores only a hash of it, so if you lose a key, revoke it and create a new one.

Can the API call anyone I send it?

No. Outbound calls queued through the API or the MCP server go through the same checks as calls started in the app: consent, the Do Not Call list and local calling hours. A blocked call is refused with a reason code, and a call outside calling hours waits until it is allowed to ring.

What is the difference between the two MCP servers?

The platform server works with your own account data (calls, leads, bookings, outbound calls, the Do Not Call list and chats) and needs an API key. The site server is public and read-only: it answers questions about Vocenya itself, such as pricing, industries and guides, and needs no key.

Is there an OpenAPI specification?

Yes. The OpenAPI document is published at /docs/api.json and the full API reference, generated from the same document, at /docs/reference. You can use the JSON to generate a client in your language.

What happens when I go over the rate limit?

Each key can make 120 requests a minute by default. Past that the API answers 429 Too Many Requests with a Retry-After header telling you how many seconds to wait.

Does the API work for practices in HIPAA mode?

Yes, with less detail. For organizations in HIPAA mode the API and MCP server leave out transcripts, summaries, chat message text and the reason and details of a lead, and webhooks carry ids only. Call recordings are never available through the API.