Documentation ›Integrations and API

Configure the agent from your own code (REST API)

Anything you can set on the Settings page, you can also set from a script — useful if you manage several locations, or if an agency runs the setup for you. Authenticate with a Full API key from Account → API keys.

Read the current settings:

curl https://sipmind.net/api/v1/agent/config \
  -H "Authorization: Bearer sk-tenant-YOUR_KEY"

Change one thing — send only the fields you want changed, everything else stays as it is:

curl -X PATCH https://sipmind.net/api/v1/agent/config \
  -H "Authorization: Bearer sk-tenant-YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"welcome_message": "Hello! How can I help?", "temperature": 0.5}'

Full reference: the developer documentation lives at sipmind.net/developers (public — you can send it to your integrator), and the machine-readable schema at /api/v1/openapi.json, which most code generators read directly.

What you can set: system_prompt, prompt_mode, business_context, welcome_message, voice, voice_speed, realtime_model, temperature, max_response_output_tokens, rag_top_k, rag_threshold, timezone, notification_language, customer_languages, spoken_facts, blocked_numbers. The GET response lists the allowed values for each, and prompt_field names the one field for your own text — business_context on every current account. How the agent behaves is ours: kept up to date, not editable and not shown. system_prompt is writable only on an account still on a prompt it wrote in full. A field name we don't recognise comes back as an error, not a silent success.

Facts said word for word. Hours, addresses and phone numbers are what a caller writes down, so give them to the agent as exact words rather than as prose in the prompt — the same list as Say these word for word in Settings. spoken_facts is {place: {fact: exact words}}; the same fact in another language is its own key, for example "hours@kk". Send the whole object each time; {} removes them all.

curl -X PATCH https://sipmind.net/api/v1/agent/config \
  -H "Authorization: Bearer sk-tenant-YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"spoken_facts": {"downtown": {"hours": "Monday to Saturday, nine to seven",
                                   "address": "15 Harbour Street, second floor"}}}'

blocked_numbers is the list of callers the agent never answers: a number, or a prefix of at least seven digits with a star, such as +1555012*. A blocked call costs nothing and leaves no transcript. voice_speed sets the speaking tempo from 0.25 to 1.5 of the voice's natural speed; null returns to natural. Every entry we cannot use is named in the error — nothing is dropped quietly.

Plan limits. The GET response also carries a limits object — the ceilings your plan puts on the length of system_prompt and business_context, on rag_top_k and on max_response_output_tokens. Those four are what drive the cost of every conversation, so the cheaper plans bound them. Read limits before you write: going over comes back as a 400 naming the field and the number, and nothing is saved. An empty object means your plan sets no ceiling. Separately, adding knowledge-base documents is bounded per day — generous enough that a real import never meets it, and a script stuck in a loop does.

Work with SIPmind from Claude. In claude.ai or the Claude app: Settings → Connectors → Add custom connector, paste https://sipmind.net/mcp, sign in here and press Allow — choose Full or Read only. Then just ask: describe the business to the agent, load the price list, show last week's leads. The connection is listed in Account → API keys and is switched off there. Developers in Claude Code, Cursor or Codex connect the same address with a key, or run the downloadable file — both are on the developer page. It can set up, read and try the agent; it deliberately cannot place calls, send paid templates or delete anything.

Try the agent from code. POST /api/v1/agent/test (the ask_agent tool) answers a customer's message exactly as a live chat would, and lists the actions it would take — save a lead, call a person in, book — without doing any of them. Nothing is sent or saved.

Events pushed to you. Set an address in Settings and every new lead is POSTed there (lead.created), signed with your secret (X-SIPmind-Signature) and retried on a server error. The rest — a lead moves, a contact is created or changed, two contacts or two leads are merged, a call ends, a visit is booked or cancelled, a task is set or done — arrive once you subscribe to them with PUT /api/v1/events/subscription; GET on the same path lists them all (see Outgoing webhooks under CRM integrations). Use them as a nudge and keep the updated_since poll as the source of truth: a delivery can be lost, a poll cannot.

This endpoint can't touch your channel tokens

It only reads and writes agent behaviour — your WhatsApp / Telegram / Instagram tokens, your own AI key and passwords are not readable and not writable here. That's deliberate: a setup script should never be able to lose a connected channel. Connect and disconnect channels in Integrations.

Connecting channels from code. GET /api/v1/channels answers where every channel actually stands — and, importantly, flags the half-connected ones: credentials stored but the provider handshake missing, which every screen would otherwise show as connected while not a single message arrives.

curl -X POST https://sipmind.net/api/v1/channels/telegram \
  -H "Authorization: Bearer sk-tenant-YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"bot_token": "123456:AA..."}'

That one call verifies the token with Telegram, stores it and registers the webhook — and returns an error rather than a green answer if the webhook does not register. Phone numbers work the same way: GET/POST /api/v1/channels/phone and DELETE /api/v1/channels/phone/{id}. Tokens are write-only everywhere: you can set them, never read them back.

WhatsApp from code. If the number already sits on a Meta app you manage, POST /api/v1/channels/whatsapp with phone_number_id (the numeric id from WhatsApp Manager — not the phone number) and, if it is your own app, its access_token. We check the token with Meta before storing anything, and refuse a number already connected to another account. Numbers that do not yet exist on any Meta app — and Instagram — still need Meta's browser flow: connect once in Integrations, then keep working from code.

Getting your data out. GET /api/v1/leads, /api/v1/calls and /api/v1/contacts return your CRM, oldest change first — /api/v1/companies too, the companies your contacts belong to. Each answer carries next_updated_since — pass it back to receive only what changed since:

curl "https://sipmind.net/api/v1/leads?updated_since=2026-08-01T00:00:00Z&limit=100" \
  -H "Authorization: Bearer sk-tenant-YOUR_KEY"

Rows sharing the cursor's exact second may repeat on the next poll, so match on id — repeating a row is safe, losing one is not. Conversation transcripts are personal data, so they are never in a list: fetch them one at a time with GET /api/v1/calls/{id}.

Pipelines and stages. Every lead names the pipeline it is on. GET /api/v1/pipelines lists your pipelines and the stages of each, with what every stage means — open, won or lost. PATCH /api/v1/leads/{id}/stage accepts only a stage of the lead's own pipeline, and the error lists the ones it does accept: a stage its board has no column for would leave the card drawn nowhere.

Complaints and questions. A pipeline that is done when the customer is answered says closes_when_answered: true in GET /api/v1/pipelines. Each lead carries answered_at and answered_via (chat, marked or ai). Answered the customer in your own system? POST /api/v1/leads/{id}/answered closes the request; calling it twice is safe.

The Instagram funnel from code. Once the account is connected in Integrations, everything after that is an API call. GET/PATCH /api/v1/channels/instagram/settings holds the switches — public replies, DM answers, moderation, replying only to codewords, the working hours and days, and what happens outside them. GET /api/v1/channels/instagram/scenarios lists your codeword scenarios; PUT /api/v1/channels/instagram/scenarios/{id} creates or edits one, DELETE removes it. GET /api/v1/channels/instagram/funnel answers how it is performing: comments seen, DMs opened, buttons tapped, leads.

curl -X PUT https://sipmind.net/api/v1/channels/instagram/scenarios/spring \
  -H "Authorization: Bearer sk-tenant-YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"keywords": ["spring", "sale"], "opener": "Here it is — tap below.",
       "buttons": ["Send it"], "magnet": "https://example.com/offer", "active": true}'

Answering like a person, not a script. A public reply that appears two seconds after the comment is the clearest sign an account is run by software — and the people reading it are your own followers. In Integrations → Instagram you can set a wait in minutes, as a range: we pick a random moment inside it for each comment, so the timing is never the same twice. Leave it at 0 and replies go out immediately, as before.

A comment containing one of your codewords is never held — that person typed the word your post asked for and is waiting. The message in their Direct was always instant and still is; only the public line under the post waits. A held reply survives a restart, and the working hours and the daily limit are re-checked at the moment it actually appears, so one queued at 20:55 for 21:10 does not slip past a 21:00 cut-off.

Who a conversation goes to, and when. GET/PATCH /api/v1/team/routing sets where the AI transfers a call — a phone, an extension on your PBX such as 602, or a whole queue such as q-sales — each under a department or colleague name the agent can choose. work_schedule ({"mon": [["09:00", "18:00"]], …} — the week, with days off; the older operator_hours [8, 18] still works as the same hours every day) and operator_holidays ("03-22" every year, "2026-12-31" once) say when someone is in: outside them the agent keeps the caller, says when people are back and takes a callback instead of ringing an empty office. The same call sets the Telegram chat that receives handovers and new leads. Tokens come back masked and a masked value is refused on write, so a read-then-write script can never quietly replace a working token with the stars it just read.

Calling out from code. GET/PATCH /api/v1/outbound/settings holds the four things outbound needs: the caller ID people see, the prompt and greeting used when we call them, and the hours the agent may dial in your own timezone. The GET also answers ready and, when it is false, exactly what is missing — a plan without telephony and a missing caller ID both end as a refused call, and knowing which one beforehand is the difference between a fixable setup and a mystery. Placing the call itself is POST /api/v1/outbound/call; GET /api/v1/outbound/dnc and POST/DELETE manage the numbers the agent must never call.

Two fields are deliberately not settable here: the carrier endpoint and the Asterisk address we dial through. We set those up with you, and a wrong value does not come back as an error — the call is placed and dies somewhere in the carrier with an empty log. A setup script should not be able to do that to a working phone line.

AI employees. GET /api/v1/employees lists them with the line each one answers and how many your plan allows; POST hires one, PATCH /api/v1/employees/{id} changes it, and PUT /api/v1/employees/{id}/lines gives it a channel — or one specific number on that channel. A new employee starts as a draft and answers nobody until you set status to active: an unfinished setup should not start talking to your customers. A line has exactly one owner, so binding a line another employee holds moves it.

Two things to know

  • The voice engine is chosen by SIPmind unless your account runs on its own AI key. Until then realtime_model reads as null, model_locked is true, and a write of it is not applied — the response says so in notice.
  • The knowledge base is fully manageable from code: GET /api/v1/documents lists it, POST adds, DELETE /api/v1/documents/{id} removes, /documents/stats counts. Leads travel both ways — POST /api/v1/leads pushes one in, PATCH /api/v1/leads/{id}/stage moves it.