Managed billing
With managed billing your app pays for the Talki accounts it activates: the customer has no Talki subscription of their own and sees no prices or payments. This page adds to OAuth apps; everything there still applies. To have an app enabled, see Become a partner.
- The customer presses «Attiva Talki» (or your own label) in your software.
- Your server mints a single-use activation with the app’s credentials.
- You send the customer’s browser to the authorization URL you already build,
with
&enrollment=…added. - The customer creates a Talki account, or signs in to an existing one, and approves. The consent screen shows that the subscription is managed by your app, and on which plan.
- The browser returns to your
redirect_uriwith acode, as in any OAuth flow. - Your server exchanges the code at
POST /oauth/token. The exchange puts the account under your management: from then on the customer does not pay Talki, and the account appears on your app’s Businesses page in the console.
Without enrollment, the same URL is an ordinary connect, and the customer needs
a subscription of their own.
Before you start
Section titled “Before you start”- The app must be approved and enabled for managed billing. Enabling is not available from the console.
- In the console, set the app’s default plan: the plan of every activation that names none. Changing it affects only activations minted afterwards, and does not send the app back to review.
- Changing the app’s name, website, logo, redirect URIs or scopes sends it back to review, and activations fail while it is in review.
- Every request on this page authenticates with the app’s credentials, as at
/oauth/token: HTTP Basic, orclient_idandclient_secretin the JSON body.GETaccepts HTTP Basic only. Keep the secret server-side. - Errors use the API envelope,
{"error": {"type", "code", "message", "request_id"}}, not the OAuth shape of/oauth/token.
Mint an activation
Section titled “Mint an activation”curl --fail-with-body https://api.talki.it/oauth/enrollments \ -u "$TALKI_CLIENT_ID:$TALKI_CLIENT_SECRET" \ -H "Content-Type: application/json" \ -d '{ "plan": "pro", "email": "giulia@salonebellini.example", "business_name": "Salone Bellini", "first_name": "Giulia", "last_name": "Bellini", "forwarding_number": "+39 333 000 0000", "external_ref": "cust_4821" }'| Field | Rule |
|---|---|
email |
Required. Only a Talki account with this address can consent to the activation, so a forwarded link does not work for anyone else. |
plan |
base, pro or business; unlimited only if it is enabled for your app. Omitted: the app’s default plan. The plan is fixed here and does not follow later changes to the default. |
business_name, first_name, last_name, forwarding_number |
Optional. Pre-fill the details the customer confirms; the customer can correct them. forwarding_number is the business’s own line, which forwards its calls to Talki. phone is its old name and still works, with the same value: if you send both, they must be the same number, or the request is refused with 400 invalid_parameter. |
external_ref |
Optional, up to 200 characters. Your own id for the customer, kept on the account’s plan history and shown in the usage report. |
201 Created:
{ "enrollment": "talki_en_…", "expires_at": "2026-10-15T09:12:00+00:00", "plan": "pro", "external_ref": "cust_4821"}- An activation is valid for 24 hours and works once. Mint a new one each time the customer presses the button; never store or reuse one.
- The
enrollmentvalue is a secret. Put it only in the authorization URL, never in logs, emails or your own pages. The consent page removes it from the address bar as soon as it reads it. - Each app may mint 60 activations per hour; beyond that the answer is
429withRetry-After. To activate many existing customers at once, plan the rollout with Talki first.
Send the customer to Talki
Section titled “Send the customer to Talki”The authorization URL from OAuth apps — PKCE S256, a
fresh code_challenge per flow — plus enrollment:
https://app.talki.it/autorizza ?response_type=code &client_id=talki_cid_4Hq2mZ8rVt1LxN3pYw7KcA &redirect_uri=https%3A%2F%2Fcrm.example.com%2Ftalki%2Fcallback &scope=account%3Aread%20calls%3Aread &state=Zk3q9… &code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM &code_challenge_method=S256 &enrollment=talki_en_…What the customer sees:
- No Talki account: a two-step signup branded with your app. First what is
being activated — your app, «managed by» your app, the plan and the scopes —
then a form: business name, first and last name, mobile number, email and
password, pre-filled from the activation. Pressing «Crea account e attiva
Talki» is the consent. After confirming the email the customer returns to your
redirect_uriwith no further screen, unless the scopes or the plan changed in the meantime, in which case the ordinary consent screen is shown. - Signup with Google or Microsoft: the consent screen, which asks for the business name and mobile number when they are missing.
- An existing account: sign in, then the consent screen.
Business name, first name, last name and mobile number are all required before
consent completes: the assistant answers with the business name, and the
mobile number becomes the account’s forwarding_number, the business’s own
line that forwards its calls to Talki. It is not a transfer target: the
assistant transfers calls only to the account’s transfer_numbers, which start
empty; set them with PATCH /v1/account.
On app.talki.it and in the Talki app, the subscription shows as managed by your app, with no prices or payments. The customer uses Talki as any other customer.
Exchange the code
Section titled “Exchange the code”The callback and the exchange are those of OAuth apps.
Keep account_id from the token response: it identifies the account to
/oauth/managed-accounts.
Bind state and the code_verifier to the browser session of the user who
pressed the button, and exchange the code only when state matches that
session. Looking the verifier up by state alone lets whoever receives a
forwarded link finish the activation in their own browser, on your bill.
On a successful exchange the account is managed by you, gets the Talki number its calls are forwarded to, and receives the plan’s minutes.
The exchange fails with invalid_grant when, between consent and exchange, the
activation expired or the account came under another management. Nothing changes
then: mint a new activation and send the customer back.
Create accounts from your server
Section titled “Create accounts from your server”The standard way to bring a customer on board is the flow above: the customer authorizes your app and consents on Talki, with an activation when your app pays.
Headless provisioning, POST /oauth/managed-accounts, creates the account from
your server instead, and the customer sees no Talki screen. It is enabled per
app, on request: write to info@talki.it with the app’s
client ID and the product it serves.
Create an account
Section titled “Create an account”curl --fail-with-body https://api.talki.it/oauth/managed-accounts \ -u "$TALKI_CLIENT_ID:$TALKI_CLIENT_SECRET" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: 3b1f0c52-6f0e-4a8e-9d43-0b2f7c1e5a10" \ -d '{ "email": "giulia@salonebellini.example", "business_name": "Salone Bellini", "first_name": "Giulia", "last_name": "Bellini", "forwarding_number": "+39 333 000 0000", "transfer_numbers": [ {"label": "Reception", "phone": "+39 045 000 0000"} ], "plan": "pro", "scopes": ["account:read", "appointments:read", "calls:read"], "external_ref": "cust_4821", "terms": { "version": "2026-10", "accepted_at": "2026-10-22T09:12:00+00:00", "ip": "203.0.113.7", "user_agent": "Mozilla/5.0 …" } }'| Field | Rule |
|---|---|
email |
Required. An address verified on your platform. An address that already has a Talki account is refused with 409 account_exists: send that customer through the activation flow instead. |
business_name, first_name, last_name |
Required, not blank. The assistant answers with the business name. |
forwarding_number |
Required. The business’s own line, which forwards its calls to Talki. transfer_phone is its old name and still works, with the same value: send one of the two, and if you send both they must be the same number, or the request is refused with 400 invalid_parameter. |
transfer_numbers |
Optional, up to 20. Who the assistant may hand a call over to, each as {"label", "phone"}, by the rules of PATCH /v1/account: labels up to 80 characters and unique ignoring case; phone numbers, a national one read as Italian, none equal to the forwarding_number. A list that breaks them is refused with 400 invalid_parameter, and nothing is created. Omitted: none, and the assistant does not transfer calls until you set them with PATCH /v1/account. |
plan |
As on an activation. Omitted: the app’s default plan. |
monthly_minutes |
Optional. The monthly minutes you sold the customer. Omitted: none, and the plan’s minutes apply. |
scopes |
The scopes the customer accepted; see below. |
external_ref |
Optional, up to 200 characters, as on an activation. |
terms |
Required. When the customer accepted Talki’s terms on your platform: version (your name for the text), accepted_at (RFC 3339 with an offset, not in the future), and optionally ip and user_agent. |
test |
true creates a test account. Default false. |
Idempotency-Key is required. A retry with the same key and body answers
200 with Idempotency-Replayed: true, the same account and a new token pair;
the earlier pair stops working. The same key with a different body is
409 idempotency_key_reuse, and a retry while the first request is still
running is 409 request_in_progress.
201 Created:
{ "account_id": "f7e39b9a-1ac8-45e4-93da-2600f17cb286", "installation_id": "5d0e8a2c-7b41-4f7e-9c3a-1e2f4b6d8a90", "talki_number": "+390212345678", "plan": "pro", "monthly_minutes": null, "external_ref": "cust_4821", "access_token": "talki_at_…", "token_type": "Bearer", "expires_in": 3600, "refresh_token": "talki_rt_…", "scope": "account:read appointments:read calls:read", "livemode": true, "account_name": "Salone Bellini", "test": false, "test_expires_at": null}- The token pair is that of an exchanged code: store and refresh it the same way.
talki_numberisnullwhen no number was free. The account is given one later, automatically; see Manage an account.- Creating accounts is limited to 30 an hour per app, replays included
(
429 rate_limit_exceeded).
| HTTP | code |
Meaning |
|---|---|---|
| 400 | invalid_parameter |
The body is not a JSON object, or a field is invalid; the message names it |
| 400 | idempotency_key_required |
Idempotency-Key is missing |
| 400 | invalid_plan |
Not a plan your app may pay for |
| 400 | invalid_scope |
See below |
| 400 | invalid_phone |
forwarding_number is not a valid number |
| 400 | cap_above_plan |
monthly_minutes is above the minutes the plan includes |
| 401 | invalid_client |
Wrong client ID or secret |
| 403 | provisioning_not_enabled |
Headless provisioning is not enabled for the app |
| 403 | app_not_approved |
The app is in review, suspended or disabled |
| 409 | account_exists |
The address already has a Talki account, or one of your live test accounts |
| 409 | plan_unavailable |
plan omitted, and the app’s default plan is no longer one it may pay for |
| 409 | test_account_limit |
The app already holds 10 test accounts |
| 409 | idempotency_key_reuse |
The key was used for a different body |
| 409 | request_in_progress |
The first request with this key is still running |
| 409 | installation_revoked |
A replay, for an account that no longer has your app installed |
| 429 | rate_limit_exceeded |
Honour Retry-After |
| 503 | api_error |
The account could not be created right now; retry with the same Idempotency-Key |
Show the permissions on your own screen
Section titled “Show the permissions on your own screen”With headless provisioning there is no Talki consent screen, so the permissions are yours to show:
- Before the customer accepts, show every scope your app will ask for, in the customer-facing wording below.
- Send in
scopesonly the scopes the customer accepted. - Without
scopes, the account grants your app every scope it is registered for except the opt-in ones,transcripts:read,calls:deleteandknowledge:write, which are granted only when listed. An app registered for opt-in scopes alone must sendscopes. scopesthat is empty, repeats a scope, or names one the app is not registered for fails with400 invalid_scope, as does a missingscopeson an app registered for opt-in scopes alone.
The customer-facing wording exists in Italian only. Show it as written to an Italian-speaking customer; in any other language, show a faithful translation of it. «What it allows» is a reference for you, not text to show the customer.
| Scope | What it allows | Customer-facing wording (Italian) |
|---|---|---|
account:read |
Assistant settings, locations, hours, closures, the Talki number, the owner’s forwarding number and its check, onboarding status and talk-time usage | Vedere i dati della tua attività e tutte le impostazioni dell’assistente: nome, fuso orario, orari di apertura, chiusure, il nome con cui risponde, voce, saluto, lingue, la zona in cui lavori, i numeri a cui passa le chiamate e le tue «Informazioni aggiuntive» e «Istruzioni aggiuntive». Anche il tuo numero Talki, il numero da cui inoltri le chiamate e se l’inoltro funziona, se hai completato la configurazione iniziale e i tuoi minuti: quanti ne hai usati, quanti ne hai a disposizione e quando si rinnovano |
account:write |
Change assistant settings (turning off transcript storage deletes stored transcripts), hours, closures and the forwarding number; start a forwarding check (places a short test call); complete onboarding | Modificare le impostazioni dell’assistente: nome dell’attività, il nome con cui risponde, voce, saluto, lingue, la zona in cui lavori, i numeri a cui passa le chiamate, orari di apertura, chiusure e aperture straordinarie, le tue «Informazioni aggiuntive» e «Istruzioni aggiuntive», e se prende appuntamenti, raccoglie le richieste, ricorda chi chiama e conserva il testo delle conversazioni (spegnendolo, quello già salvato viene cancellato). Anche cambiare il numero da cui inoltri le chiamate, avviare la verifica dell’inoltro, che fa una breve chiamata di prova al tuo numero, e segnare come completata la configurazione iniziale |
calls:read |
Call log, summaries, stats and counts, PDF/Excel export of the same, and calls Talki refused before answering (with the caller’s number) | Leggere le chiamate ricevute: chi ha chiamato, quando, quanto è durata e il riassunto di ogni conversazione, con le statistiche e l’esportazione in PDF o Excel di questi stessi dati. Anche le chiamate che Talki non ha potuto accettare, ad esempio perché i minuti erano finiti, con il numero di chi chiamava |
calls:write |
Mark calls read or unread, archive and restore them | Segnare le chiamate come lette o da leggere, e archiviarle o ripristinarle |
calls:delete |
Permanently delete calls, each with its transcript, the questions it left and the caller names heard on it; appointments stay | Eliminare definitivamente le chiamate ricevute, insieme al testo della conversazione, alle richieste che l’agente non ha saputo risolvere e ai nomi sentiti dall’assistente che non hai ancora aggiunto. Una chiamata eliminata non si può recuperare; gli appuntamenti presi durante la chiamata restano in calendario |
transcripts:read |
Full text of call conversations | Leggere il testo completo delle conversazioni con i tuoi clienti |
appointments:read |
Calendar appointments | Vedere tutti gli appuntamenti in calendario |
appointments:write |
Book, move and cancel appointments | Prendere, spostare e disdire appuntamenti a tuo nome |
contacts:read |
Contact book, tags, caller names heard on calls, VIP and blocked numbers, blocked call attempts | Vedere la tua rubrica: nomi, numeri e note di ogni contatto, quante volte ha chiamato e le etichette. Anche i nomi che l’assistente ha sentito da chi chiama e che non hai ancora aggiunto, i numeri VIP e bloccati con il nome che hai dato a ognuno, e le chiamate rifiutate perché il numero era bloccato |
contacts:write |
Create, update and delete contacts, tags and VIP or blocked numbers; approve or discard heard names | Aggiungere, modificare ed eliminare i contatti in rubrica, creare, rinominare ed eliminare etichette e assegnarle, confermare o scartare i nomi sentiti dall’assistente, e aggiungere, cambiare o togliere numeri VIP e bloccati |
services:read |
Services offered and pricing | Vedere il tuo listino: servizi, durate e prezzi |
services:write |
Create, modify, deactivate and delete services | Aggiungere servizi al listino, modificarne nomi, durate e prezzi, disattivarli ed eliminarli |
resources:read |
Resources, capacity and seat availability | Vedere le tue risorse: postazioni, sale, attrezzature |
resources:write |
Create shared resources, and modify and delete resources | Aggiungere, modificare ed eliminare le risorse: postazioni, sale, attrezzature |
unresolved:read |
Requests the agent could not resolve | Vedere le richieste che l’agente non ha saputo risolvere: il numero di chi ha chiamato e cosa ha chiesto |
unresolved:write |
Resolve, dismiss or reopen unresolved requests | Segnare come gestite, scartare o riaprire le richieste che l’agente non ha saputo risolvere |
knowledge:read |
The assistant’s documents (files, text notes, websites and their imported pages), each one’s status and the text read from it, and the original files | Vedere i Documenti dell’assistente: i file, i testi e i siti caricati, con le pagine importate, lo stato di ognuno e il testo che ne ha ricavato, e scaricare i file originali |
knowledge:write |
Add, replace, rename, switch on or off and delete documents (files, text notes, websites and single imported pages), and teach the assistant new answers; the assistant uses what is added with every caller | Gestire i Documenti dell’assistente: aggiungere, sostituire, rinominare, attivare o disattivare ed eliminare file, testi, siti e singole pagine importate, e insegnare nuove risposte. L’assistente userà questi contenuti con chiunque chiami |
availability:read |
Free and bookable slots | Vedere quando sei libero e quando sei occupato |
Manage an account
Section titled “Manage an account”GET https://api.talki.it/oauth/managed-accounts/{account_id}PUT https://api.talki.it/oauth/managed-accounts/{account_id} {"plan": "base"}DELETE https://api.talki.it/oauth/managed-accounts/{account_id}POST https://api.talki.it/oauth/managed-accounts/{account_id}/suspendPOST https://api.talki.it/oauth/managed-accounts/{account_id}/reactivatePOST https://api.talki.it/oauth/managed-accounts/{account_id}/minutesGET https://api.talki.it/oauth/managed-accounts/{account_id}/minutescurl --fail-with-body -X PUT \ https://api.talki.it/oauth/managed-accounts/f7e39b9a-1ac8-45e4-93da-2600f17cb286 \ -u "$TALKI_CLIENT_ID:$TALKI_CLIENT_SECRET" \ -H "Content-Type: application/json" \ -d '{"plan": "base"}'GET, PUT, DELETE, /suspend and /reactivate answer with the account’s
state:
{ "account_id": "f7e39b9a-1ac8-45e4-93da-2600f17cb286", "plan": "pro", "scheduled_plan": "base", "scheduled_at": "2026-10-31T23:00:00+00:00", "monthly_minutes": 80, "minutes_included": 80, "managed_since": "2026-10-07T11:09:43+00:00", "ends_at": null, "test": false, "test_expires_at": null, "talki_number": "+390212345678", "line_status": "verified", "suspended": false, "suspended_at": null, "suspension_reason": null, "extra_seconds_balance": 7230, "extra_minutes_balance": 120, "partner_notifies_customer": false}| Field | Meaning |
|---|---|
plan |
The plan your app pays for |
scheduled_plan, scheduled_at |
A downgrade waiting for the 1st, and when it applies; see Change the plan |
monthly_minutes |
The monthly minutes you set; null when none is set, or once the customer has taken the account over with their own subscription |
minutes_included |
The minutes the account’s month includes, against which its calls are refused: the plan’s, lowered or capped by monthly_minutes. null when nothing caps them |
managed_since |
When your app started paying for the account |
ends_at |
Set once management has ended: access, and your bill, run to this moment; see End management |
test, test_expires_at |
Set on a test account |
talki_number |
The Talki number the business forwards its calls to; null while none is assigned |
line_status |
The same value as line.status on GET /v1/account: whether forwarding to talki_number is proven |
suspended, suspended_at, suspension_reason |
Whether the service is suspended, since when and with which reason; suspended_at and suspension_reason are null when it is not |
extra_seconds_balance, extra_minutes_balance |
The extra minutes on the account as they stand now; minutes are rounded down |
partner_notifies_customer |
true while your app notifies the customer itself |
An account_id your app does not manage answers 404 not_managed, whether the
account exists or not. Each of these routes allows 120 requests per minute per
address.
An account created with no free number is given one automatically as soon as one
is, unless management has already ended: talki_number stops being null, and your app receives an account.updated
app event with the account’s phone_number when it subscribes to
that event and holds account:read.
Change the plan
Section titled “Change the plan”- An upgrade applies at once.
- A downgrade applies on the 1st of the next month, Italian time, and
shows in
scheduled_planandscheduled_atuntil then. - A new change replaces the scheduled one; changing back to the current plan cancels it.
unlimitedhas no minute cap and Business limits otherwise. It is accepted only when enabled for your app, and ranks abovebusiness: moving onto it applies at once, moving off it on the 1st of the next month.
Set the monthly minutes
Section titled “Set the monthly minutes”monthly_minutes is the number of minutes a month you sold the customer: once the
month has used them, and any extra minutes, the account’s
calls are refused, with reason minutes in GET /v1/refused_calls, until its
minutes renew. Send it on create or with PUT, as a whole
number from 1 to 100,000:
curl --fail-with-body -X PUT \ https://api.talki.it/oauth/managed-accounts/f7e39b9a-1ac8-45e4-93da-2600f17cb286 \ -u "$TALKI_CLIENT_ID:$TALKI_CLIENT_SECRET" \ -H "Content-Type: application/json" \ -d '{"monthly_minutes": 80}'PUTtakesplan,monthly_minutes, or both."monthly_minutes": nullremoves the allowance; leaving the field out keeps it.- On a plan with a minute cap,
monthly_minutescan only lower the plan’s minutes. Above them the answer is400 cap_above_planand nothing changes. It is checked against the plan in the same request, otherwise against the current plan and a scheduled downgrade. Aplansent alone that includes fewer minutes than the allowance already set is400 cap_above_plantoo: send a lowermonthly_minutes, ornull, in the same request. - On a plan with no cap,
unlimited,monthly_minutesbecomes the cap. - A change applies at once, both ways, unlike a plan downgrade: raising it lets the next call through, and lowering it below what the month has already used sends the next call to extra minutes, or refuses it when there are none.
minutes_includedon the account shows the result, and the usage events report it; their threshold also counts the account’s extra minutes.- An activation carries no
monthly_minutes: set it withPUTafter the exchange. An activation for an account you still manage keeps its allowance, and when the activation’s plan includes fewer minutes, the exchange fails withinvalid_grant. - Once management has ended,
monthly_minutescan no longer change (409 partner_ending). The allowance applies untilends_at, unless the customer takes the account over with their own subscription first.
Suspend and reactivate an account
Section titled “Suspend and reactivate an account”Suspend the service of an account, for example when the customer stops paying you:
curl --fail-with-body -X POST \ https://api.talki.it/oauth/managed-accounts/f7e39b9a-1ac8-45e4-93da-2600f17cb286/suspend \ -u "$TALKI_CLIENT_ID:$TALKI_CLIENT_SECRET" \ -H "Content-Type: application/json" \ -d '{"reason": "non_payment", "note": "Invoice 2026-118 unpaid"}'| Field | Rule |
|---|---|
reason |
Required. non_payment or other. |
note |
Optional, up to 500 characters. Stored with the suspension; the API never returns it. |
While the account is suspended:
- its calls are refused, with
reasonsuspendedinGET /v1/refused_calls; POST /v1/forwarding_checkandPOST /v1/agent_testanswer409 account_suspended, and the customer cannot test the assistant or use the assistant chat in the Talki apps;- the customer is told in the Talki apps that the service is suspended and to
contact your app.
reasonandnoteare not shown in the Talki apps, but the customer’s export of their own data includes them.
Everything else keeps working: the customer’s login and data, the Talki number,
your app’s access to /v1 and its app events. The plan runs on
and the account stays on your bill.
POST .../reactivate takes no fields and lifts the suspension at once. Both routes
are idempotent by state and answer 200 with the account: a second /suspend
keeps the first suspension’s date, reason and note, and /reactivate on an
account that is not suspended changes nothing.
A suspension holds until you reactivate the account, through the grace month
after DELETE included. It stops applying when the customer takes the account
over with their own subscription, and /suspend then answers
409 partner_ending.
Add extra minutes
Section titled “Add extra minutes”Add minutes to an account, for example a pack the customer bought on your platform:
curl --fail-with-body -X POST \ https://api.talki.it/oauth/managed-accounts/f7e39b9a-1ac8-45e4-93da-2600f17cb286/minutes \ -u "$TALKI_CLIENT_ID:$TALKI_CLIENT_SECRET" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: 9c4d2e71-0b3a-4f65-8e1d-6a7b2c9f0e34" \ -d '{"minutes": 120, "order_ref": "ord_2291"}'| Field | Rule |
|---|---|
minutes |
A whole number from 1 to 100,000. |
seconds |
A whole number from 60 to 6,000,000. Send exactly one of minutes and seconds. |
order_ref |
Optional, up to 200 characters. Your own order id, returned as sent. |
201 Created, with the account’s extra minutes after the grant:
{ "object": "minute_grant", "id": "3e8b1f2a-6c4d-4a9e-b7f0-1d2c3b4a5e6f", "account_id": "f7e39b9a-1ac8-45e4-93da-2600f17cb286", "seconds": 7200, "minutes": 120, "order_ref": "ord_2291", "livemode": true, "created_at": "2026-10-20T10:04:11+00:00", "extra_seconds_balance": 7230, "extra_minutes_balance": 120}Idempotency-Key is required. A retry with the same key and body answers 200
with Idempotency-Replayed: true and the same grant, with the balance as it
stands now; nothing is added twice. The same key with a different body, or for
another account, is 409 idempotency_key_reuse.
How the minutes are spent:
- They are spent only after the month’s
minutes_included, and carry over from month to month. - On a plan with no cap and no
monthly_minutesthey are never spent; the grant is still recorded. - The customer cannot buy extra minutes on an account you manage; only your server adds them.
- Once management has ended, no minutes can be added (
409 partner_ending). A retry of an earlier grant is still answered untilends_at, and with404 not_managedafter it. - At
ends_atthe remaining minutes are lost, unless the customer has taken the account over with their own subscription: then they stay on the account.
minutes and extra_minutes_balance are whole minutes, rounded down; the
seconds figures are exact. The grants show in
GET /oauth/app/usage as minute_grants.
GET .../minutes lists the grants your app made to the account, newest first, as
{"object": "list", "data", "has_more", "next_cursor"}. Query: limit (1 to
100, default 25) and cursor (a previous page’s next_cursor).
End management
Section titled “End management”DELETE keeps the customer active, on your bill, until the end of the current
month (ends_at). The customer receives an email saying so, with a reminder to
turn off call forwarding, unless your app
notifies its customers itself. After ends_at the
account is an ordinary Talki account and its Talki number is released; unless the
customer subscribes, your installation receives
installation.access_suspended. Once management has ended, the
plan and monthly_minutes can no longer change and no minutes can be added.
Management also ends, the same way, when the customer disconnects your app, or
when your app revokes the installation. Calling
/oauth/revoke with any live token revokes the whole
installation and therefore ends management — do not call it when one of your
users logs out; discard the token instead.
The console’s Businesses page offers the plan change and the end of management: the plan picker, the «Managed by you» badge and «End management». An app that manages accounts cannot be deleted until management of each has ended.
API access on any plan
Section titled “API access on any plan”Through your app, a managed account reaches /v1 and app events
on every plan, not only Business. The customer’s own API keys, and any other
app, still need Business.
Usage events
Section titled “Usage events”Your app receives usage.threshold_reached and usage.extra_credits_low for
each account it pays for, at its events URL, like app events. It
needs no subscription and no scope for them, and no other app receives them.
Their fields are listed in
Usage events.
- They are sent only while your app pays for the account and its installation
is active. They stop at once when the customer disconnects your app or your
app revokes the installation. When you end management with
DELETE, they keep coming untilends_at, or until the customer subscribes on their own if that comes first. - Neither is sent while nothing caps the account’s minutes: an account on
unlimitedsends them only when you set itsmonthly_minutes.
Notify customers yourself
Section titled “Notify customers yourself”When your app notifies its customers itself, the customers of the accounts it
manages receive no email or push notification from Talki: no welcome email, no
notifications about calls or minutes, and no end-of-management email when your
app ends management. Tell them from the app events your app
receives. Messages with no event of their own are not sent either: read refused
calls from GET /v1/refused_calls, and tell the customer yourself when their
calendar stops syncing.
It is enabled per app, on request, for an app enabled for managed billing: write to info@talki.it with the app’s client ID and the product it serves. It applies at once to every account the app manages.
- It applies while your app manages the account and is installed on it, the
grace month after
DELETEincluded. Talki’s own messages resume when the customer disconnects your app, takes the account over with their own subscription, or reachesends_at. - The end-of-management email is still sent when management ends without your app ending it, for example when the customer disconnects your app.
- Always sent, whatever the setting: account security emails such as email confirmation and password reset, legal notices, receipts for purchases the customer makes, service-wide maintenance notices, and notifications about the customer’s own webhook endpoints or store subscription.
partner_notifies_customeron the account istruewhile it applies to that account.
Monthly usage
Section titled “Monthly usage”The console’s Usage page, on an app enabled for managed billing, shows the month’s usage of every account you manage:
- totals for each plan (duration, calls, businesses),
unlimitedfirst; - one row per business, with your
external_refand its split by plan. Businesses that deleted their Talki account are grouped in one row, and their calls still count; - Export CSV: one line per business and plan, with the columns
business_name, external_ref, account_id, plan, seconds, calls, duration.
How usage is counted:
- To the second, never rounded. Durations display as whole minutes plus the
remaining seconds (
12,345 min 17 s); the CSV’ssecondscolumn is exact. - By the month the call was answered, Italian time. A call belongs entirely to the month and plan it was answered in, even when it ends after midnight on the 1st or after a plan change.
- Only calls answered while you managed the account are counted.
Read usage from your server
Section titled “Read usage from your server”GET /oauth/app/usage returns the same month to your server, with the client
credentials over HTTP Basic. It covers the accounts your app pays for only.
curl --fail-with-body "https://api.talki.it/oauth/app/usage?month=2026-10" \ -u "$TALKI_CLIENT_ID:$TALKI_CLIENT_SECRET"{ "object": "usage_report", "month": "2026-10", "livemode": true, "plans": [ {"plan": "pro", "partner_only": false, "seconds": 5400, "calls": 31}, {"plan": "unlimited", "partner_only": true, "seconds": 32170, "calls": 263} ], "businesses": [ { "account_id": "f7e39b9a-1ac8-45e4-93da-2600f17cb286", "business_name": "Studio Bellini", "external_ref": "CUST-42", "plans": [ {"plan": "pro", "partner_only": false, "seconds": 5400, "calls": 31}, {"plan": "unlimited", "partner_only": true, "seconds": 30960, "calls": 254} ], "minute_grants": {"seconds": 7200, "count": 1} }, { "account_id": null, "business_name": "Account eliminato", "external_ref": null, "plans": [ {"plan": "unlimited", "partner_only": true, "seconds": 1210, "calls": 9} ], "minute_grants": {"seconds": 0, "count": 0} } ], "minute_grants": {"seconds": 7200, "count": 1}}| Parameter | Rule |
|---|---|
month |
YYYY-MM, Italian time. Omitted: the current month, still counting |
format |
json (default) or csv |
livemode |
true (default): calls on real accounts. false: only the fake calls on your test accounts |
- Every figure is per plan:
planstotals each plan across all businesses, and each business lists its own plans. Bill each customer from its plan entries; there is no total across plans. format=csvreturns the console’s export columns,business_name, external_ref, account_id, plan, seconds, calls, duration, one line per business and plan.- Calls are counted as on the Usage page: to the second, whole, in the month and on the plan they were answered on, and only while your app managed the account.
- Businesses that deleted their Talki account share one row with
account_id: null. - A business your app is no longer installed on keeps its
account_idandexternal_ref, withbusiness_name: null. - Usage is recorded from 14 October 2026: earlier months are empty, and so is every month of an app that manages no account.
livemodein the answer is the mode you asked for. Test usage is never mixed into the live report.minute_grants, on each business and at the top level, totals the extra minutes your app added in the month, Italian time:secondsadded andcountof grants, in the mode you asked for. A business that only had minutes added is listed with emptyplans. The CSV leaves them out.
Errors use the API envelope: 401 invalid_client for wrong credentials, 400 invalid_parameter for a bad month, format or livemode, and 409 client_disabled for an app Talki has disabled. Past 60 requests per minute per
address the answer is 429, with Retry-After.
Errors
Section titled “Errors”| HTTP | code |
Where | Meaning |
|---|---|---|---|
| 400 | invalid_parameter |
All | The body is not a JSON object, a field is invalid, or a query or path parameter is malformed; the message names it |
| 400 | idempotency_key_required |
POST /oauth/managed-accounts, /minutes |
Idempotency-Key is missing |
| 400 | invalid_plan |
Activations, PUT |
Not a plan your app may pay for; the message lists them |
| 400 | invalid_phone |
Activations | The forwarding_number hint is not a valid number |
| 400 | cap_above_plan |
POST /oauth/managed-accounts, PUT |
monthly_minutes is above the minutes the plan includes, or a plan includes fewer minutes than the monthly_minutes already set |
| 401 | invalid_client |
All | Wrong client ID or secret |
| 403 | not_a_billing_partner |
Activations | The app is not enabled for managed billing |
| 404 | not_managed |
Managed accounts | Your app does not manage that account |
| 409 | partner_ending |
PUT, /minutes, /suspend |
Management has ended: the plan and monthly_minutes can no longer change and no minutes can be added. On /suspend: the customer has taken the account over with their own subscription |
| 409 | idempotency_key_reuse |
POST /oauth/managed-accounts, /minutes |
The key was used for a different request |
| 409 | extra_minutes_limit |
/minutes |
The account cannot hold that many extra minutes |
| 429 | rate_limit_exceeded |
Activations, managed accounts | Honour Retry-After |
The customer can meet these on the consent screen. They are explained there, in Italian, and the customer is not sent back to you:
code |
Meaning | What to do |
|---|---|---|
enrollment_invalid |
The activation expired or was already used | Mint a new one |
email_mismatch |
The activation is for a different email | The customer signs in with the email you gave, or you mint one with the right email |
already_subscribed |
The account has its own Talki subscription | The customer cancels it, or uses another account |
managed_by_another_partner |
Another app already manages the account | The customer uses another account |
partner_ending |
Management of the account has just ended | It can be activated again from the 1st of the next month |
plan_unavailable |
The activation’s plan is no longer one your app may pay for | Mint a new activation |
When an activation expires before the customer completes it, the account they created stays. On their next visit to Talki they are told to go back to your software and press the button again: mint a new activation, and they sign in with the account they already have.
Test the integration
Section titled “Test the integration”- Your sandbox account can be activated through the existing-account path, with no real business.
- With headless provisioning enabled, create test accounts from your server and try plans, suspension, extra minutes, fake calls and the usage report on them.
- For the full path with a new customer — signup, confirmation email, plans other than Business — ask Talki for a test environment.
Test accounts
Section titled “Test accounts”An app enabled for headless provisioning
creates a test account by sending "test": true in the body of
POST /oauth/managed-accounts. The request is checked like a real one,
Idempotency-Key included, and the answer has the same shape, with
"test": true and test_expires_at. A test account:
- has no Talki number (
talki_numberisnull), sends no email and is billed to nobody; - is in test mode:
livemodeisfalsein the token answer, onGET /v1/account, in/oauth/app/installationsand on every event it sends; - is erased within the hour after
test_expires_at, 7 days after it was created.
Your app may hold 10 test accounts whose test_expires_at has not passed; one
more answers 409 test_account_limit. Creating accounts, test ones included, is
limited to 30 an hour per app (429 rate_limit_exceeded). An email address already used for one
of your live test accounts answers 409 account_exists.
GET, PUT and DELETE /oauth/managed-accounts/{account_id}, /suspend,
/reactivate and /minutes work on a test account as on a real one, so plan
changes, monthly minutes, suspension, extra minutes and the end of management
can be tried in full. Fake calls are not refused while a test account is
suspended: read the suspension from the account.
Give it calls
Section titled “Give it calls”A test account has no API key. Drive the sandbox scenarios on it with the access token your app received for it:
curl --fail-with-body -X POST https://api.talki.it/v1/sandbox/calls \ -H "Authorization: Bearer $TALKI_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{"scenario": "call_no_action", "caller_phone": "+393480000001"}'POST /v1/sandbox/callsandGET /v1/sandbox/scenariosaccept the token of the app that created the account, untiltest_expires_at. Any other token answers403 sandbox_api_key_required.- A test account starts with no weekly hours and no services.
booking_createdbooks 10:00 Italian time on a Tuesday to Saturday one to four weeks ahead. So first set weekly hours that cover 10:00 on those days withPUT /v1/working_hours(for example{"slots": [{"days": [2, 3, 4, 5, 6], "start": "09:00", "end": "18:00"}]}). Then create a service with aduration_minutesand aninitial_capacitywithPOST /v1/services.booking_rescheduledandbooking_cancelledact on an upcoming booking at the main location. When the account lacks what a scenario needs, the call answers400 sandbox_not_ready. POST /v1/sandbox/resetanswers403 forbidden: a test account is never reset. Create another one instead.
Test usage
Section titled “Test usage”A fake call on a test account counts like a real call:
- its seconds go to the account’s minutes, in
GET /v1/usageandGET /v1/usage/history, and the usage events are sent at the same thresholds, withlivemode: false; - it is in
GET /oauth/app/usage?livemode=false, on the plan it was answered on. Withformat=csvthe file is named<client_id>-usage-<month>-test.csv.
It never appears in the live report, on the console’s Usage page or on an invoice.
Minutes added to a test account have livemode: false and are counted in
minute_grants with livemode=false only.
