Vocatech

Developer Guide

Everything you need to integrate with the Vocatech API for call reporting, messaging, contact management, and real-time webhooks.

Overview

The Vocatech API is a REST API that gives you access to:

  • Call history — Search and filter call records with full journey details.
  • Message history — Search SMS and WhatsApp message records.
  • Messaging — Send SMS messages through your Vocatech numbers.
  • Contacts — Manage integration contacts: pull lists, push updates, and sync from external systems.
  • Webhooks — Subscribe to real-time call and message events delivered to your endpoint.

Base URL

https://api.vocatech.com/v1

All API endpoints are relative to this base URL. For example, to list calls:

GET https://api.vocatech.com/v1/calls

Authentication

All requests require a Bearer token in the Authorization header:

Authorization: Bearer YOUR_API_KEY

Your API key is scoped to a single company. All queries are automatically filtered to your company's data.

Keep your API key secret. Never expose it in client-side code, public repositories, or URLs. If compromised, contact Vocatech support to rotate your key.

Example Request

curl -X GET "https://api.vocatech.com/v1/calls" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json"

Calls

MethodEndpointDescription
GET /calls Search call history with filters

Query Parameters

ParameterTypeRequiredDescription
start_datedateNoStart date (YYYY-MM-DD). Defaults to today.
end_datedateNoEnd date (YYYY-MM-DD). Defaults to today.
directionstringNoincoming, outgoing, or any (default)
statusstringNoanswered, missed, or any (default)
searchstringNoSearch by call ID, name, or extension
pageintegerNoPage number
limitintegerNoResults per page (max 500)

Example

curl "https://api.vocatech.com/v1/calls?start_date=2026-03-01&end_date=2026-03-10&direction=incoming" \
  -H "Authorization: Bearer YOUR_API_KEY"

Call Journey

Each call record includes a journey array showing every segment of the call in chronological order:

FieldTypeDescription
typestringAutoAttendant, HuntGroup, CallCenter, or User
namestringName of the entity (e.g., "Main Menu", "Sales Queue", "John Doe")
extensionstringExtension number
start_timedatetimeWhen this segment started
durationintegerSegment duration in seconds
answeredbooleanWhether the call was answered in this segment

Messages

MethodEndpointDescription
POST /messages Send an SMS message
GET /messages Search message history

Send a Message

curl -X POST "https://api.vocatech.com/v1/messages" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "platform": "text",
    "from": "5551234567",
    "to": "5559876543",
    "message": "Hello from Vocatech!"
  }'
Dry-run mode. Add "test": true to the request body to validate without actually sending. Returns a 200 with validation results instead of creating any resources.

Message History Parameters

ParameterTypeRequiredDescription
start_datedateNoStart date (YYYY-MM-DD)
end_datedateNoEnd date (YYYY-MM-DD)
directionstringNoincoming, outgoing, or any
channelstringNotext, whatsapp, or any
statusstringNodelivered, failed, read, or any

Media

The unified GET /v1/media/{id} endpoint provides authenticated access to all media files — SMS/MMS attachments, WhatsApp media, and call recordings. The ID prefix determines the media type.

MethodEndpointDescription
GET /media/{id} Get media metadata and download URL

ID Prefixes

PrefixTypeExampleSource
att_Message attachment/v1/media/att_456SMS/MMS images, WhatsApp photos, documents, voice notes
rec_Call recording/v1/media/rec_84729Call recording audio from call journey segments

Message Attachments (att_)

When a message includes media, the attachments array in the message response or webhook payload contains attachment objects:

{
  "message_id": "sms_12345",
  "direction": "incoming",
  "channel": "text",
  "body": "Check out this photo!",
  "attachments": [
    {
      "id": "att_456",
      "content_type": "image/jpeg",
      "filename": "photo1.jpg",
      "size": 245760
    }
  ]
}

Download the attachment:

curl "https://api.vocatech.com/v1/media/att_456" \
  -H "Authorization: Bearer YOUR_API_KEY"

Supported Media Types

ChannelSupported Types
SMS/MMSImages (JPEG, PNG, GIF), contacts, and other MMS-supported formats
WhatsAppImages, video (MP4), audio (MP3, OGG, AMR), documents (PDF, DOCX, XLSX), contacts (VCF)
Text-only messages have an empty attachments array. The attachments field is always present. For text-only messages it will be [].

Call Recordings (rec_)

Call recordings are accessed through the same /v1/media endpoint using the rec_ prefix with the segment ID from the call journey.

How It Works

  1. Call GET /v1/calls to retrieve call reports — each journey segment includes a recording_url field (null if no recording exists).
  2. The recording_url points to /v1/media/rec_{segment_id} — call it to get a 30-minute signed download URL.
  3. Download the MP3 file directly using the signed URL (no auth header needed for the download itself).
curl "https://api.vocatech.com/v1/media/rec_84729" \
  -H "Authorization: Bearer YOUR_API_KEY"

Recording Response

{
  "id": "rec_84729",
  "type": "recording",
  "content_type": "audio/mp3",
  "format": "mp3",
  "duration": 185,
  "url": "https://storage.googleapis.com/...signed...",
  "expires_at": "2026-03-20T19:30:00.000Z"
}

Notes

  • Signed URLs expire after 30 minutes. Request a new URL by calling the endpoint again.
  • Only media belonging to your company is accessible — ownership is verified automatically.
  • Not all call segments have recordings. Check the recording_url field in the call journey — if null, no recording is available.

Contacts

Manage your integration contacts programmatically. Pull existing contact lists, push new contacts, or sync from external systems like CRMs and property management software.

MethodEndpointDescription
GET /contacts/fields List your contact field schema
GET /contacts List contacts (paginated, searchable)
POST /contacts Create or update contacts (single or batch)
DELETE /contacts Delete contacts (single or batch)

Step 1: Get Your Field Schema

Before pushing contacts, call GET /contacts/fields to see what fields are configured for your company:

curl "https://api.vocatech.com/v1/contacts/fields" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response:

{
  "fields": [
    { "id": 12, "name": "Company", "is_phone": false, "is_match": true, "is_integration": false },
    { "id": 18, "name": "Phone", "is_phone": true, "is_match": false, "is_integration": false },
    {
      "id": 20, "name": "Portal", "is_phone": false, "is_match": false,
      "is_integration": true,
      "integration": {
        "id": 1, "initials": "AP",
        "fields": [
          { "key": "contact_url", "display_name": "Contact URL", "value": "https://admin.vocatech.com/company/?company_id={CONTACT_ID}" },
          { "key": "default_url", "display_name": "Default URL", "value": "https://admin.vocatech.com" }
        ]
      }
    }
  ]
}
Understanding field types.
  • Match fields (is_match: true) are used for deduplication. When you push a contact, if ALL match fields match an existing contact, it updates instead of creating a duplicate.
  • Phone fields (is_phone: true) auto-format values to digits. They support multiple numbers separated by semicolons (e.g., "5551234567;5559876543").
  • Integration fields (is_integration: true) are clickable connectors with initials and URLs. The field value acts as a reference ID for generating links.

Step 2: List Existing Contacts

curl "https://api.vocatech.com/v1/contacts?page=1&limit=100" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response:

{
  "query": { "page": 1, "limit": 100, "search": null },
  "contacts": [
    {
      "id": 181119,
      "fields": {
        "Company": "ABC Mortgage",
        "Contact": "John Smith",
        "Phone": "2125551234;2125559999;2125550100",
        "Portal": "9105222634"
      }
    }
  ],
  "meta": {
    "page": 1,
    "limit": 100,
    "total_pages": 19,
    "total_contacts": 1858
  }
}

Query Parameters

ParameterTypeRequiredDescription
pageintegerNoPage number (default: 1)
limitintegerNoResults per page, max 500 (default: 100)
searchstringNoSearch across all field values

Step 3: Push Contacts

Send a single contact:

curl -X POST "https://api.vocatech.com/v1/contacts" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "fields": {
      "Company": "ABC Mortgage",
      "Contact": "John Smith",
      "Phone": "2125551234;2125559999;2125550100",
      "Portal": "9105222634"
    }
  }'

Response (201 if created, 200 if updated):

{
  "summary": { "total": 1, "created": 1, "updated": 0, "errors": 0 },
  "contacts": [
    {
      "contact": {
        "id": 181119,
        "fields": {
          "Company": "ABC Mortgage",
          "Contact": "John Smith",
          "Phone": "2125551234;2125559999;2125550100",
          "Portal": "9105222634"
        }
      },
      "action": "created"
    }
  ],
  "errors": []
}
Phone numbers are auto-formatted. Phone fields are automatically cleaned to digits-only. Sending "917-555-9999" or "(917) 555-9999" becomes "9175559999". Multiple numbers can be sent in a single phone field separated by semicolons: "5551234567;5559876543;5554441111". Each number is formatted individually and duplicates are removed.

Batch Push

Send up to 500 contacts at once by using the contacts array:

curl -X POST "https://api.vocatech.com/v1/contacts" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "contacts": [
      { "fields": { "Company": "ABC Mortgage", "Phone": "2125551234;2125559999", "Portal": "9105222634" } },
      { "fields": { "Company": "XYZ Corp", "Phone": "7185558888", "Portal": "9105333745" } }
    ]
  }'

Response:

{
  "summary": { "total": 2, "created": 1, "updated": 1, "errors": 0 },
  "contacts": [ ... ],
  "errors": []
}

Delete Contacts

Delete a single contact by ID:

curl -X DELETE "https://api.vocatech.com/v1/contacts" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "id": 12345 }'

Delete multiple contacts:

curl -X DELETE "https://api.vocatech.com/v1/contacts" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "ids": [12345, 12346, 12347] }'

Webhooks

Webhooks let you receive real-time notifications when call or message events occur. Create an endpoint, subscribe to events, and we'll send HTTP POST requests to your URL.

MethodEndpointDescription
GET /webhooks List all webhook endpoints
POST /webhooks Create a webhook endpoint
GET /webhooks/{id} View a webhook endpoint
PATCH /webhooks/{id} Update a webhook endpoint
DELETE /webhooks/{id} Delete a webhook endpoint
POST /webhooks/{id}/test Send a test delivery
GET /webhooks/failures List failed deliveries

Create a Webhook

curl -X POST "https://api.vocatech.com/v1/webhooks" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "My CRM Webhook",
    "url": "https://yourapp.com/webhook",
    "event_filters": ["call.started", "call.ended", "message.received", "message.sent"]
  }'
Save your secret key! The secret_key is only returned when you create the webhook. Store it securely — you'll need it to verify delivery signatures.

Event Types

EventWhen it fires
call.startedA call leg begins (dialled or received)
call.answeredA call leg is answered
call.endedA call leg finishes
call.transcriptionAI processing completes (5-30 min after call ends)
Message Events
message.sentAn outgoing SMS or WhatsApp message is sent
message.receivedAn inbound SMS or WhatsApp message arrives
message.status_updatedDelivery status changes (sent → delivered → read)

Subscribe to one or more events via the event_filters array. You can mix call and message events in a single webhook.

You can also filter by extension using extension_filters to only receive call events for specific extensions.

Message webhook latency. Outgoing message webhooks may have up to ~60 seconds latency (polled by scheduler). Inbound message events are delivered in real-time (seconds).

Webhook Payloads

When an event fires, your endpoint receives a JSON POST with this structure:

{
  "id": "evt_67890abcdef",
  "event_type": "call.ended",
  "timestamp": "2026-03-10T14:30:45+00:00",
  "company_id": 123,
  "data": {
    "call_id": "c045ac31-abbe-45dc-9722-efbe4044cc73",
    "direction": "incoming",
    "extension": "101",
    "extension_name": "John Doe",
    "remote_name": "Jane Smith",
    "remote_number": "5551234567",
    "group_number": "5559876543",
    "start_time": "2026-03-10T14:30:00.000Z",
    "end_time": "2026-03-10T14:31:10.000Z",
    "duration": 70
  }
}

For call.started and call.answered events, the end_time and duration fields are not included.

Message Event Payload

Message events use the same envelope with a different data shape. The attachments array is always present (empty for text-only messages):

{
  "id": "evt_msg_abc12345",
  "event_type": "message.received",
  "timestamp": "2026-03-15T14:30:45+00:00",
  "company_id": 123,
  "data": {
    "message_id": "sms_789012",
    "direction": "incoming",
    "channel": "text",
    "from": "+14155551234",
    "to": "+17185550000",
    "body": "Check out this photo!",
    "status": "delivered",
    "sent_at": "2026-03-15T14:30:45.000Z",
    "attachments": [
      {
        "url": "https://api.vocatech.com/v1/media/att_456",
        "content_type": "image/jpeg",
        "filename": "photo1.jpg",
        "size": 245760
      }
    ]
  }
}
FieldTypeDescription
message_idstringUnique message identifier
directionstringincoming or outgoing
channelstringtext (SMS) or whatsapp
fromstringSender phone number (E.164)
tostringRecipient phone number (E.164)
bodystringMessage text content
statusstringsent, delivered, read, or failed
sent_atdatetimeWhen the message was sent (UTC)
attachmentsarrayMedia attachments (empty array [] for text-only messages). Each object has url, content_type, filename, and size.

For message.status_updated events, the data object includes the new status value and an updated_at timestamp. The read status is only available for WhatsApp messages.

For call.transcription events, the data object also includes:

FieldTypeDescription
summarystringAI-generated call summary
transcriptionstringFull transcript text

Signature Verification

Every delivery includes an X-Vocatech-Signature header for security:

X-Vocatech-Signature: t=1710000000,v1=5257a8...b4c2e9

How to Verify

1. Extract the timestamp (t) and signature (v1) from the header.

2. Compute the expected signature:

// PHP
$expected = hash_hmac('sha256', "t={$timestamp}.{$rawBody}", $secretKey);

// Node.js
const expected = crypto
  .createHmac('sha256', secretKey)
  .update(`t=${timestamp}.${rawBody}`)
  .digest('hex');

// Python
import hmac, hashlib
expected = hmac.new(secret_key.encode(), f"t={timestamp}.{raw_body}".encode(), hashlib.sha256).hexdigest()

3. Compare: if v1 matches your computed value, the delivery is authentic.

4. Replay protection: reject if abs(current_time - t) > 300 (5 minutes).

Retry Policy

If your endpoint returns a non-2xx status code or times out, we retry with exponential backoff:

AttemptDelay
1st retry1 minute
2nd retry5 minutes
3rd retry30 minutes
4th retry2 hours

After 5 total attempts, the delivery is marked as failed. View failures at GET /webhooks/failures.

Your endpoint should respond within 10 seconds. Process the webhook asynchronously if your logic takes longer. Return a 200 immediately and handle the event in a background job.

Webhook Testing

Two ways to test your webhooks:

1. Test Tool (no server needed)

Use our interactive test tool at api.vocatech.com/test. It creates a temporary receiver URL so you can see exactly what payloads look like.

2. Send a Test Delivery

Send a test event to your actual endpoint:

curl -X POST "https://api.vocatech.com/v1/webhooks/{id}/test" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

This sends a webhook.test event to the endpoint's URL with a valid signature.

Rate Limits

Rate limits are applied per API key:

TierEndpointsLimits
Default Most endpoints 60/min • 1,000/hr • 20,000/day
Reports GET /calls, GET /messages 30/min • 500/hr • 10,000/day
Messaging POST /messages 5 per 10 minutes

When exceeded, the API returns 429 Too Many Requests with a Retry-After header indicating how many seconds to wait.

Errors

The API uses standard HTTP status codes. Error responses include a JSON body:

{
  "error": {
    "code": 404,
    "type": "RESOURCE_NOT_FOUND",
    "message": "Webhook endpoint not found."
  }
}
CodeMeaning
200Success
201Created
204Deleted (no content)
400Bad request (missing or invalid fields)
401Unauthorized (invalid or missing API key)
403Forbidden (no access to this resource)
404Not found
409Conflict (deprecated — existing resources are now reused)
422Validation error
429Rate limit exceeded

Pagination

List endpoints support pagination with page and limit query parameters:

GET /v1/calls?page=2&limit=50

Responses include a meta object:

{
  "meta": {
    "page": 2,
    "limit": 50,
    "total_pages": 10,
    "total_calls": 487
  }
}

Need help? Contact support@vocatech.com