API keys
Machine access for your own systems — create a key, scope it to one job, and connect your website, CRM or automation tool.
On this page
The panel is for people. The API is for your systems: a website form that pushes enquiries in, a CRM that pulls call results out, a nightly sync, a Zapier connector.
Account → API KeysNote
This page covers managing keys — creating, scoping and revoking them. The full endpoint reference (paths, parameters, response schemas) is served separately at api.vocallie.com/v1/docs.
Creating a key
Give it a label describing where it'll be used — "Website form", "Zapier", "Nightly CRM sync". When the key is created you get the full value once.
Careful
Copy it immediately. Keys are stored hashed, so there's no way to show it again — if you lose it, you revoke it and create another. That's deliberate: a leaked database can't give anyone a working key.
Afterwards, the list shows only a short prefix, which is enough to identify a key without exposing it.
Scopes
A key can be limited to specific jobs. Available scopes:
| Scope | Allows |
|---|---|
leads:read / leads:write | Read or create and update contacts and notes |
calls:read / calls:write | Read call records, transcripts and recordings / place calls |
appointments:read / appointments:write | Read or create, complete and cancel bookings |
followups:read / followups:write | Read or manage follow-ups and callback requests |
campaigns:read / campaigns:write | Read or create and control campaigns |
webhooks:read / webhooks:write | Read or manage webhook subscriptions |
usage:read | Read your usage and balance |
Two design decisions worth knowing:
- Write does not imply read. A key that only pushes contacts in from your website form has no business reading your contact list back out. Grant both if you need both.
calls:writeis deliberately separate fromleads:write, because placing calls spends your wallet. An import-only credential can't dial.
Scopes can't be added to an existing key. Widening means creating a new key — so a permission can't be quietly granted to a credential already out in the wild.
Tip
One key per integration, scoped to exactly what it needs. When something goes wrong, you revoke one key and one integration stops — rather than everything.
Expiry and revocation
Keys can be given an expiry date at creation. A key past its date is rejected with a clear message naming the date, so nobody spends an afternoon hunting for a typo.
Revoke disables a key immediately. Revoked keys stay in the list so you keep the audit trail.
The list also shows last used, which is how you answer "is this key still needed?" before revoking something.
What you can do with the API
At a product level:
- Contacts — import in bulk, update, add notes, read them back.
- Calls — list them, read transcripts, get a recording link, and place a call to a contact.
- Follow-ups — schedule, cancel, complete; read pending callback requests.
- Appointments — create, cancel, complete, and list them (including cancelled ones, so a calendar sync can remove them).
- Campaigns — create, add contacts, start, pause and resume.
- Webhooks — manage subscriptions programmatically.
- Usage — check your balance and consumption.
Using it safely
- Keys belong on your server, never in browser JavaScript or a mobile app. For a public web page, use the website widget, which has a key designed to be public.
- Rotate on staff changes. Revoke and reissue when someone with access leaves.
- Use
Idempotency-Keyon writes. Send a unique value per operation and a retry after a timeout replays the original result instead of creating a duplicate. Essential for anything that places a call or creates a booking. - Handle rate limits. Requests are limited per key per minute; the response headers tell you where you stand. Back off when you see a 429 rather than retrying immediately — retries don't consume your event quota, but they don't get you served faster either.
Things that surprise people
- Imports skip rows without a valid phone number. The response tells you how many were imported and which were skipped, so check it rather than assuming your count went through.
- Contact de-duplication uses your own
external_id. Without one, a retry can create duplicates — another reason to use an idempotency key. - Bulk imports don't fire automations by default. That's a safety measure: turning it on for a 10,000-row sync could trigger rules that call the entire list.
- Recording links are short-lived and minted per request, rather than stored URLs.
- Some fields are read-only. Things the platform maintains — a contact's call status, their next follow-up time — are rejected rather than silently ignored if you try to set them.
Events quota
API requests consume your monthly events allowance, shared with webhooks. A chatty polling integration burns through it faster than a webhook-driven one — which is a good reason to prefer webhooks for "tell me when something happens" and the API for "let me fetch what I need".
More events are available as an add-on.