Skip to content
Website

REST API and authentication ​

This page covers the routes that accept a Voxido API key: the inbound route that creates or updates contacts, and a test route for checking your key.

Base URL: https://api.voxido.ai/api/v1

API keys ​

FactDetail
Format43 URL-safe characters, no prefix
HeaderX-API-Key: <your key>
Stored by VoxidoOnly a SHA-256 hash and the first 8 characters. The full key is shown once.
ExpiryNone. A key works until it's revoked.
Permissions (scopes)inbound:write lets a key post to inbound APIs.

Get a key with inbound:write from the inbound API's panel: Integrations → Custom API → Inbound → open the API → Generate key. Keys from Settings → API keys → Generate key get a different default scope and are refused by inbound APIs. See Create and manage API keys.

POST /inbound/ ​

Creates or updates one contact from a JSON body, using the field mapping you set on the inbound API. Copy the full URL from the inbound API's Endpoint URL field.

bash
curl -X POST "https://api.voxido.ai/api/v1/inbound/3f6c…" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $VOXIDO_INBOUND_KEY" \
  -d '{"full_name": "Priya Sharma", "mobile": "+919812345678", "service": "Annual check-up"}'

Request ​

PartRule
X-API-Key headerAn active key of the same company, with inbound:write
BodyOne JSON object, at most 1 MB
FieldsAny names. Your mapping decides which become contact fields.

Success: 200 ​

json
{
  "status": "ok",
  "contact_id": "8b1d…",
  "result": "created",
  "goal_fired": false,
  "assignee": null
}
FieldValues
resultcreated, updated, or skipped (nothing to match on, such as no email or phone)
goal_firedtrue if the inbound API's After update goal ran
assigneematched, not_found, ambiguous, not_in_workspace, or null when you don't map an owner

Errors ​

StatusBodyWhat to do
401{"detail": "Unauthorized"}Wrong, revoked or wrong-company key, a key without inbound:write, or an unknown endpoint. Voxido doesn't say which, on purpose.
413"Payload exceeds the 1 MB inbound limit"Send less data
422"Request body must be valid JSON" / "Request body must be a JSON object"Send one JSON object, not an array
422{"detail": "Missing required mapping fields", "missing_required_fields": [...]}Send the fields marked Required in the mapping
422{"detail": "Unknown …"}A routing value didn't match any workspace
429"Rate limit exceeded. Please try again later."Wait for Retry-After seconds

Each request is handled on its own. If you retry the same body, Voxido matches the same contact again (by the inbound API's Match existing contact by setting), so a retry updates rather than duplicates. An After update goal, if set, runs again.

POST /api-keys/test-signature ​

A safe route for checking your key, and your HMAC code, before you go live. It changes nothing.

Key only ​

bash
curl -X POST "https://api.voxido.ai/api/v1/api-keys/test-signature" \
  -H "X-API-Key: $VOXIDO_KEY"

Returns 200 with "message": "API key is valid!" and the key's first characters.

Key and signature ​

Add two headers:

  • X-Timestamp — the current Unix time in seconds.
  • X-Signature — lowercase hex HMAC-SHA256 of the string "{timestamp}.{raw body}", using your full API key as the secret.
python
import hashlib, hmac, json, time, requests

key = "YOUR_API_KEY"
body = json.dumps({"hello": "world"})          # sign exactly these bytes
ts = str(int(time.time()))
sig = hmac.new(key.encode(), f"{ts}.{body}".encode(), hashlib.sha256).hexdigest()

r = requests.post(
    "https://api.voxido.ai/api/v1/api-keys/test-signature",
    data=body,                                   # send the same bytes
    headers={"X-API-Key": key, "X-Timestamp": ts, "X-Signature": sig,
             "Content-Type": "application/json"},
)
print(r.json())
ResultResponse
Valid key, valid signature200, "message": "API key and signature are valid!"
Valid key, wrong signature200, "success": false, "message": "Signature mismatch", with your signature and the expected one
No X-API-Key400, "Missing X-API-Key header. Send your API key to test."
Unknown or revoked key401, "Invalid API key. Make sure you're using the full secret key (not just the prefix)."
Timestamp more than 5 minutes off401, "Timestamp expired. Server time: …"

This signature format is only for the test route

Inbound APIs authenticate with the key alone. Webhook triggers use a different signature (HMAC of the raw body, no timestamp). See Webhook triggers: payload and HMAC signing.