AI receptionist API: set it up from code
An AI receptionist API is a list of HTTP calls, not a library. You create a business, store what the receptionist may say, name which of the owner's phones get a transfer, have a person pay, and then order a US local number. Do the steps in that order. A number against an empty brief is a line that can only apologize. RingKit's API is at https://api.ringkit.com/v1. There are no SDKs yet. Use curl or fetch. The same routes are described in an OpenAPI 3.1 document at https://api.ringkit.com/openapi.json. The format of that document is the OpenAPI 3.1 specification. If you wanted the tool list an agent calls inside a chat app, that is the MCP phone receptionist. This page is the HTTP underneath it.
The full sequence, with every field, is the quickstart in the docs. What follows is the order that matters, the two places a person has to act, and the mistakes that create a second number or an empty brief.
Create the business, and keep the key
POST /v1/businesses is the only call that needs no API key. Send a name, an IANA timezone, and the owner's email. Leave ownerPhone off. The API refuses it on create with 403 destination_unverified, because a business that does not exist yet cannot have proved it controls a phone. You add the owner's mobile later, after a verification call. The response is 201 with the business id and the API key. The key is shown once. Store it before you do anything else.
Send an Idempotency-Key on that POST. Retrying the same key within 24 hours returns the stored response and the header Idempotent-Replayed: true, instead of creating a second business. A retry that arrives while the first request is still running gets 409 idempotency_in_progress. A new key means you meant a new business. Use a new key only when you mean that.
curl https://api.ringkit.com/v1/businesses \
-H "Content-Type: application/json" \
-H "Idempotency-Key: create-northside-1" \
-d '{"name":"Northside Example","timezone":"America/Phoenix","ownerEmail":"[email protected]"}'
That body is a sample, not a real company. Put the key on every later call as Authorization: Bearer rk_…. A key acts as the owner. Scope manage is the default. Scope read can only GET, and anything else returns 403 insufficient_scope. Give a reporting script a read key. Do not give it the key that can order numbers.
Teach the line before you buy the number
The receptionist will say what you store, and it will not invent a policy that is not there. You can import a website in the background with POST /v1/businesses/$BIZ/knowledge/imports and a URL, then poll GET /v1/businesses/$BIZ/onboarding until latestImport.status is done or failed. The import fills only fields that are still empty. It does not replace a price someone already typed, and it does not touch an uploaded document. Read the result before you trust it. A homepage price can be a sale that ended.
Or replace the profile yourself with PUT /v1/businesses/$BIZ/knowledge, or merge with PATCH. Hours, services, prices you will stand behind, FAQs, and policies are the fields callers hear. Or upload a PDF, DOCX, TXT, Markdown, or HTML file, up to 10 MB, as base64. Or start a setup chat and answer in sentences. All of those land in the same profile.
The receptionist does not book a calendar. A caller who asks for a time becomes a message in the summary. Do not write a prompt that says the appointment is confirmed.
Transfers are the owner's phones
PUT /v1/businesses/$BIZ/routing replaces the whole policy. Fields you leave out go back to their defaults, so send the full rule, not a fragment. Set mode to ai_only. The receptionist answers every call. transferTargets is a list of the business's own numbers, each with an id, a label, the number, and a whenToUse the model can follow. "The caller asks for the owner" is a usable rule. "Emergencies" is not, unless you also wrote what you mean by one. If nobody is free, or no rule matches, it takes a message. RingKit does not staff the call. Modes that used to bring in a RingKit live rep are not offered, and they run as ai_only.
Voice is optional. GET /v1/voices lists them. PATCH the business with a voice id, or leave the default. Do this before you judge a simulation. A test of the wrong voice wastes a billed call and tells you nothing about the brief.
Two steps a person still has to do
There is no free trial, and there is no sandbox. POST /v1/businesses/$BIZ/simulate runs the real receptionist on typed lines. An empty callerText returns the greeting. Send the callId back with the next line. That test is billed from the wallet at the AI rate, $0.20 a minute. Do not tell anyone the simulation is free. If the wallet is empty, fund it before you rely on the test.
A top-up is POST /v1/businesses/$BIZ/wallet/top-ups with amountCents of at least 1000, which is $10. The response is a checkout URL. A person opens it and pays. The API does not charge a card by itself. Send an idempotency key, and reuse it only for that same top-up. After they pay, GET the wallet and confirm the paid balance. Ordering a number needs $2 of paid credit. Without it, the order returns 402 funding_required.
Order the number, then prove the phone
Search GET /v1/numbers/search?areaCode=602 and order with POST /v1/businesses/$BIZ/numbers and the number you picked. The number is $1.99 a month from the wallet. Nobody has to sign in first. Use an idempotency key on the order. A new key is a new attempt, not a replay. The business can publish that number, or keep the one customers already know and forward it. RingKit does not port numbers. The details of a live number, after it exists, are in AI agent phone number.
A real test call only rings a number the business configured and verified. POST …/destinations/verify places a call that reads a 6-digit code. That code is the person's consent to be called. POST …/destinations/confirm sends the code back. POST …/test-call then rings that number from the RingKit number, on the AI, billed at the AI rate. The docs cap test calls at 5 per business per day, and outbound calls at 3 per number per day. Your code cannot hear the code. Ask the person.
When the call is over
GET /v1/businesses/$BIZ/calls is cursor-paginated. One call includes the transcript and a summary: who called, what they needed, and the next step. You can also register a webhook with POST /v1/businesses/$BIZ/webhooks and a list of events. The secret comes back once. RingKit then POSTs call.completed, message.taken, or balance.low to your URL. balance.low fires when a call takes the wallet under $2.
Every delivery has X-RingKit-Signature: t=<unix seconds>,v1=<hex>. The hex is an HMAC-SHA256 of the timestamp, a period, and the raw body, keyed with that secret. Reject a delivery older than five minutes, and verify against the raw bytes, not a re-serialized JSON object. The check itself is in the docs. Respond 2xx within 5 seconds. Other responses are retried with backoff, up to 10 attempts, except a 4xx other than 408 or 429, which is treated as permanent.
Calls are recorded and transcribed to make the summary, and a consent notice plays on every call. The receptionist always says it is an AI. That is not a flag you turn off.
What you should not build on top
Do not look for a client library, a CRM connector, or a calendar booking route. They are not in this API. Do not send ownerPhone on create and then retry with a fresh idempotency key when it fails. Fix the body and keep the story straight: verify the phone, then patch it on. Do not order the number before the brief is something the owner has read. The pricing page is the rate card: $1.99 a month for the number, $0.20 a minute on the call, first 10 seconds free, then 6-second increments. A month with no calls is $1.99.
The owner invite is optional. POST …/owners/invite emails a sign-in link. The line can run before they open it. When they do, they can rotate the key. You can keep operating either way. The API's job is the setup. The receptionist's job starts when a stranger dials the number.