Skip to content

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.

  1. The customer presses «Attiva Talki» (or your own label) in your software.
  2. Your server mints a single-use activation with the app’s credentials.
  3. You send the customer’s browser to the authorization URL you already build, with &enrollment=… added.
  4. 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.
  5. The browser returns to your redirect_uri with a code, as in any OAuth flow.
  6. 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.

  • 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, or client_id and client_secret in the JSON body. GET accepts 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.
Terminal window
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 enrollment value 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 429 with Retry-After. To activate many existing customers at once, plan the rollout with Talki first.

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_uri with 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.

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.

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.

Terminal window
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_number is null when 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

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 scopes only 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:delete and knowledge:write, which are granted only when listed. An app registered for opt-in scopes alone must send scopes.
  • scopes that is empty, repeats a scope, or names one the app is not registered for fails with 400 invalid_scope, as does a missing scopes on 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
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}/suspend
POST https://api.talki.it/oauth/managed-accounts/{account_id}/reactivate
POST https://api.talki.it/oauth/managed-accounts/{account_id}/minutes
GET https://api.talki.it/oauth/managed-accounts/{account_id}/minutes
Terminal window
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 '{"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.

  • An upgrade applies at once.
  • A downgrade applies on the 1st of the next month, Italian time, and shows in scheduled_plan and scheduled_at until then.
  • A new change replaces the scheduled one; changing back to the current plan cancels it.
  • unlimited has no minute cap and Business limits otherwise. It is accepted only when enabled for your app, and ranks above business: moving onto it applies at once, moving off it on the 1st of the next month.

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:

Terminal window
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}'
  • PUT takes plan, monthly_minutes, or both. "monthly_minutes": null removes the allowance; leaving the field out keeps it.
  • On a plan with a minute cap, monthly_minutes can only lower the plan’s minutes. Above them the answer is 400 cap_above_plan and nothing changes. It is checked against the plan in the same request, otherwise against the current plan and a scheduled downgrade. A plan sent alone that includes fewer minutes than the allowance already set is 400 cap_above_plan too: send a lower monthly_minutes, or null, in the same request.
  • On a plan with no cap, unlimited, monthly_minutes becomes 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_included on 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 with PUT after 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 with invalid_grant.
  • Once management has ended, monthly_minutes can no longer change (409 partner_ending). The allowance applies until ends_at, unless the customer takes the account over with their own subscription first.

Suspend the service of an account, for example when the customer stops paying you:

Terminal window
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 reason suspended in GET /v1/refused_calls;
  • POST /v1/forwarding_check and POST /v1/agent_test answer 409 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. reason and note are 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 minutes to an account, for example a pack the customer bought on your platform:

Terminal window
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_minutes they 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 until ends_at, and with 404 not_managed after it.
  • At ends_at the 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).

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.

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.

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 until ends_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 unlimited sends them only when you set its monthly_minutes.

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 DELETE included. Talki’s own messages resume when the customer disconnects your app, takes the account over with their own subscription, or reaches ends_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_customer on the account is true while it applies to that account.

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), unlimited first;
  • one row per business, with your external_ref and 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’s seconds column 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.

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.

Terminal window
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: plans totals 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=csv returns 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_id and external_ref, with business_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.
  • livemode in 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: seconds added and count of grants, in the mode you asked for. A business that only had minutes added is listed with empty plans. 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.

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.

  • 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.

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_number is null), sends no email and is billed to nobody;
  • is in test mode: livemode is false in the token answer, on GET /v1/account, in /oauth/app/installations and 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.

A test account has no API key. Drive the sandbox scenarios on it with the access token your app received for it:

Terminal window
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/calls and GET /v1/sandbox/scenarios accept the token of the app that created the account, until test_expires_at. Any other token answers 403 sandbox_api_key_required.
  • A test account starts with no weekly hours and no services. booking_created books 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 with PUT /v1/working_hours (for example {"slots": [{"days": [2, 3, 4, 5, 6], "start": "09:00", "end": "18:00"}]}). Then create a service with a duration_minutes and an initial_capacity with POST /v1/services. booking_rescheduled and booking_cancelled act on an upcoming booking at the main location. When the account lacks what a scenario needs, the call answers 400 sandbox_not_ready.
  • POST /v1/sandbox/reset answers 403 forbidden: a test account is never reset. Create another one instead.

A fake call on a test account counts like a real call:

  • its seconds go to the account’s minutes, in GET /v1/usage and GET /v1/usage/history, and the usage events are sent at the same thresholds, with livemode: false;
  • it is in GET /oauth/app/usage?livemode=false, on the plan it was answered on. With format=csv the 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.