Getting started
Quickstart
1. Create an API key
- Sign in to the Voximate dashboard and open Settings → API keys.
- Click New key, give it a name that says where it is used (for example “CRM sync”), and tick the scopes it needs. For this guide:
agents:read,calls:read,calls:writeandwebhooks:write. - Copy the key. It starts with
vox_live_and is shown only once.
export VOXIMATE_API_KEY="vox_live_…"2. Check the key
GET /me returns the key’s workspace and scopes. A 401 here means the key is wrong, expired or revoked.
curl https://api.voximate.no/public/v1/me \
-H "Authorization: Bearer $VOXIMATE_API_KEY"3. Find an agent
List your agents and pick one that is published — only a published agent places calls. To make a new agent from code, see Create an agent and Publish an agent.
curl "https://api.voximate.no/public/v1/agents?limit=20" \
-H "Authorization: Bearer $VOXIMATE_API_KEY"4. Start a call
Ask the agent to call a number. to is in E.164 format (+47 and the number). When the agent has exactly one phone number you can leave out from. Put your own ids in metadata: they come back on the call and in every webhook about it.
curl -X POST "https://api.voximate.no/public/v1/calls" \
-H "Authorization: Bearer $VOXIMATE_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"agent_id": "7c3f1e90-5a44-4b21-9c07-2ed5b8f41a66",
"to": "+4712345678",
"metadata": { "crm_contact_id": "48213" }
}'The answer is 202 Accepted with the call in status queued. The phone rings straight away.
Real phones ring
+4712345678 in these examples is a placeholder that cannot ring anyone: replace it with your own mobile to hear the agent.5. Get the result
Register a webhook endpoint once, and Voximate posts call.completed to it when the call has ended and its analysis is ready. Store the secret from the response — you need it to verify each delivery.
curl -X POST "https://api.voximate.no/public/v1/webhooks" \
-H "Authorization: Bearer $VOXIMATE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/voximate/webhooks",
"events": ["call.completed", "call.failed"]
}'Then verify the signature on every delivery before you trust it:
// npm install express
import crypto from 'node:crypto';
import express from 'express';
const app = express();
const SECRET = process.env.VOXIMATE_WEBHOOK_SECRET; // "whsec_…", shown once
// The signature covers the RAW body, so read it as bytes, not parsed JSON.
app.post('/voximate/webhooks', express.raw({ type: 'application/json' }), (req, res) => {
const header = req.get('Voximate-Signature') ?? '';
const parts = Object.fromEntries(header.split(',').map((p) => p.trim().split('=')));
const t = Number(parts.t);
const v1 = parts.v1 ?? '';
// Refuse old or future-dated deliveries (replay protection).
if (!Number.isFinite(t) || Math.abs(Date.now() / 1000 - t) > 300) {
return res.status(400).send('stale signature');
}
const expected = crypto
.createHmac('sha256', SECRET)
.update(`${t}.`)
.update(req.body) // Buffer — the exact bytes received
.digest('hex');
const a = Buffer.from(expected, 'hex');
const b = Buffer.from(v1, 'hex');
if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
return res.status(400).send('bad signature');
}
const event = JSON.parse(req.body.toString('utf8'));
// Events can arrive more than once: skip ids you have already handled.
console.log(event.id, event.type);
res.sendStatus(200); // answer fast; do slow work after acknowledging
});
app.listen(3000);The event’s data.object is the full call, with analysis filled in. For every line that was said, fetch the transcript:
curl "https://api.voximate.no/public/v1/calls/3c27f11c-8a1e-4d55-9b0e-1f4c2a7d9e10/transcript" \
-H "Authorization: Bearer $VOXIMATE_API_KEY"