Skip to content

Configure the assistant

A platform that manages a business’s set-up from its own panel can change what the assistant tells callers, how it speaks, when the business takes bookings, and what it offers. The owner edits the same settings in Talki, so read before you write, send the version you read, and keep your copy current with the events at the end of this page.

Setting Read Write
Business information, instructions, voice GET /v1/account PATCH /v1/account
Name, opening and greeting, switches, transfer numbers GET /v1/account PATCH /v1/account
Talki number, forwarding number GET /v1/account PATCH /v1/account (forwarding number)
Forwarding check GET /v1/forwarding_check POST /v1/forwarding_check
Onboarding GET /v1/account POST /v1/account/complete_onboarding
Voices on offer GET /v1/voices —
Weekly hours GET /v1/working_hours PUT /v1/working_hours
Closures and special openings GET /v1/closures POST, PATCH and DELETE /v1/closures
Services GET /v1/services POST, PATCH and DELETE /v1/services
Resources GET /v1/resources POST, PATCH and DELETE /v1/resources
Answers taught to the assistant GET /v1/documents?faq=true POST /v1/unresolved_requests/{request_id}/teach
Knowledge base: notes, files, websites GET /v1/documents POST, PUT, PATCH and DELETE /v1/documents

Reading the account, voices, hours, closures and the forwarding check needs account:read; writing them needs account:write. Writing a service needs services:write, a resource resources:write, and teaching an answer or writing the knowledge base knowledge:write; reading the knowledge base needs knowledge:read.

The account, the weekly hours and the forwarding check are those of one location: the main one, or the one ?location_id= names. An account whose multi_sede is false has only the main location, and the requests on this page need no location_id. For an account with several, see Work with locations.

GET /v1/account returns two texts the owner writes in Talki, under «Informazioni aggiuntive» and «Istruzioni aggiuntive»:

  • business_information — facts the assistant can tell callers: “parking is free in the courtyard”, “we do not sell gift cards”. Up to 2,000 characters.
  • instructions — short orders about how the assistant behaves on a call: “always use the formal register”, “never quote prices for colour treatments”. Up to 600 characters. A few short orders work better than a long text: the longer it is, the less likely each order is to be followed.

Both are null when empty. Neither is the assistant’s full set of instructions: each sits inside Talki’s own rules for calls, which the API does not return and cannot change. Write facts and orders about this business, as the owner would.

PATCH /v1/account takes these two, voice, and every setting in the next sections. Send the fields you change; an omitted field is left as it is. null or "" clears a text. A body with no writable field is refused with 400 invalid_parameter.

Terminal window
curl --fail-with-body -X PATCH https://api.talki.it/v1/account \
-H "Authorization: Bearer $TALKI_API_KEY" \
-H 'If-Match: "9c1e4b7a2f0d4c68b35e7a1d9f2c6b40"' \
-H "Content-Type: application/json" \
--data '{"instructions":"Always use the formal register."}'

PATCH /v1/account also takes the business name (business_name), which name the assistant answers as (answers_as), the start of the first sentence (call_opening) and the line after it (greeting), the switches (multilingual_enabled, bookings_enabled, unresolved_requests_enabled, remember_callers, store_transcripts, notify_on_every_call, notify_on_incoming_call), the area served (service_area), the people a call can be handed to (transfer_numbers) and when read calls are archived on their own (call_auto_archive_days). The reference describes each one. These behave differently from a plain value:

  • call_opening needs a plan that includes a custom opening, or the write is refused with 403 plan_feature_unavailable. Clearing it is allowed on every plan.
  • store_transcripts: false deletes every transcript already stored, at once and for good. A test-mode credential sending it is refused with 409 livemode_required.
  • transfer_numbers replaces the whole list. An empty list needs nothing else. A non-empty one needs a forwarding_number, stored or sent in the same request, and none of its numbers may equal it. Each label is at most 80 characters and unique in the list, ignoring case. With several locations, the rules cover every location’s line; see Configure one location.
  • forwarding_number is held to the same rule from the other side: it cannot equal one of the transfer_numbers, and cannot be cleared while the list has entries, unless the same request replaces the list.
  • notify_on_every_call and notify_on_incoming_call control push notifications to the owner’s Talki mobile app only, and reach nobody until the owner has signed in there. To notify by email or SMS, send your own message on call.ended or appointment.created.
  • call_auto_archive_days is the account’s own setting, the same at every location. Send it without location_id, or with the main location’s: with another location’s, the request is refused with 400 invalid_parameter. The nightly archiving sends call.updated for each call, with origin.source system.
  • languages is read only: every call opens in primary (it), and the assistant can switch to any language in supported. multilingual_enabled is what changes it.

A business’s own line forwards its calls to the Talki number, phone_number on the account. Store that line as forwarding_number, then POST /v1/forwarding_check: Talki rings it from its own number, and with forwarding on the call comes straight back. Poll GET /v1/forwarding_check every few seconds; within about a minute status is verified or not_detected. A check places a real call, so it is refused with a test-mode credential (409 livemode_required).

Each location runs one check at a time and at most 3 an hour, and an OAuth app at most 30 an hour across all the accounts it is installed on. Past either, the answer is 429 check_quota_exceeded with a Retry-After header in seconds. 503 checks_busy also carries Retry-After; 502 check_call_failed means the call could not be placed, so retry later.

Changing forwarding_number discards the last result: last_verified_at reads null until a check of the new number succeeds. phone_number is read-only; Talki assigns and releases it, and both send account.updated.

line on the account sums this up for a status screen: no_number while the account has no Talki number, unverified until a check of the current forwarding_number succeeds, then verified with verified_at. A check that finds no forwarding leaves it unchanged; read that result from GET /v1/forwarding_check.

When the business has finished setting up in your interface, call POST /v1/account/complete_onboarding, so the Talki app does not take the owner through its own setup again.

GET /v1/voices lists the voices the assistant can speak with, and the account’s voice is one of their ids. Set it with PATCH /v1/account and {"voice": "Sulafat"}; an ID not in the list is refused with 400 invalid_parameter, and voice cannot be cleared.

Each voice has a preview_url: a path relative to https://api.talki.it that returns a short WAV sample. It needs the same credential as any other request, so a browser cannot load it directly: fetch it on your server and pass the audio on to your panel.

GET /v1/working_hours returns slots. Each slot is a start–end range in the account’s timezone on one or more days, numbered as ISO weekdays: 1 is Monday, 7 is Sunday. A day with a lunch break has two slots.

PUT /v1/working_hours replaces the whole week, and a slot you leave out is an opening removed. To change one day, read the hours, edit the list, and send all of it back with If-Match:

{
"slots": [
{ "days": [2, 3, 4, 5], "start": "09:00", "end": "13:00" },
{ "days": [2, 3, 4, 5], "start": "14:30", "end": "19:00" },
{ "days": [6], "start": "09:00", "end": "17:00" }
]
}
  • end must be after start, so a range cannot cross midnight: send two slots, one ending at 23:59 and one starting at 00:00 on the next day.
  • At most 20 slots.
  • An empty list removes every regular opening: the assistant then offers callers no regular time to book.

The new hours apply at once, both to GET /v1/availability and to the next caller.

A closure is a dated exception to the weekly hours, in one of two forms:

  • whole days: all_day: true with start_date and end_date, both included;
  • an exact range: start_at and end_at, RFC 3339 with an offset.

Sending fields of both forms is refused. During a closure the assistant offers callers no time and GET /v1/availability reports nothing free. reason is optional, and the assistant can tell callers, so write it as something to say: “Christmas holidays”.

Terminal window
curl --fail-with-body -X POST https://api.talki.it/v1/closures \
-H "Authorization: Bearer $TALKI_API_KEY" \
-H "Idempotency-Key: closure-2026-12-24" \
-H "Content-Type: application/json" \
--data '{"all_day":true,"start_date":"2026-12-24","end_date":"2026-12-26","reason":"Christmas holidays"}'

A closure without location_id applies at every location of the account. To close one location only, send its location_id in the body; it cannot be moved to another location later.

Appointments already inside a closure are not cancelled. After creating one, list GET /v1/appointments with starts_after and starts_before over the closed range, and let the business decide what to move.

GET /v1/closures?from=2026-10-01&to=2026-12-31 lists the closures that overlap those local days, earliest first, in one page. Without parameters it covers a year from today; to can be at most 366 days after from.

PATCH /v1/closures/{closure_id} changes one; to move it, send the whole new window in one of the two forms. DELETE /v1/closures/{closure_id} removes it, and the days it covered follow the weekly hours again. POST requires an Idempotency-Key. Send one on DELETE too: without it, a retried DELETE that had already succeeded answers 404.

A special opening adds bookable hours to one day. Create it with kind: "open" and an exact range that starts and ends on the same day in the account’s timezone; ending at the next midnight is allowed, and a range that reaches into another day is refused with 400 invalid_parameter. Whole days are for closures only. The opening’s hours are added to that day’s weekly hours: on a day the business is normally shut they are its only hours, and on a working day they extend it. A closure on the same day still wins over both. For several days, create one opening per day. GET /v1/closures lists closures unless you pass kind=open or kind=all.

GET and PATCH /v1/account, and GET and PUT /v1/working_hours, return an ETag header. Send it back as If-Match on your next write. If the settings changed since you read them, the write is refused with 412 precondition_failed and nothing is stored: read again, reapply your change to the fresh copy, and retry with the new tag.

  • The account’s tag covers every field PATCH /v1/account can write. A change to phone_number or onboarding_completed does not move it.
  • A write that asks for exactly what is already stored succeeds whatever If-Match says. Retrying a write whose response was lost is therefore safe: the first attempt moved the tag, and the retry is not refused for having succeeded.
  • * always matches. A weak tag (W/"…") never does.
  • Without If-Match, the write replaces whatever is stored.
  • A 412 is not stored against the request’s Idempotency-Key, so the retry with the fresh tag can reuse the same key.
  • A response replayed from an Idempotency-Key carries no ETag. Read again for a current one.

Tags are opaque: store them as strings and do not parse them.

POST /v1/services creates a service with a fixed duration, active and bookable at once. Send at most one of:

  • initial_capacity — how many bookings of this service can overlap. The service gets a resource of its own, which the resource feed lists with its owner_service_id.
  • resource_ids — existing resources the service draws on, one unit of each per booking.

With neither, the service draws on its location’s default resource (is_default), the one the location’s other services share. Sending both is refused with 400 invalid_parameter, and so is sending neither while the location has no default resource yet. Both creates take ?location_id=, the main location without it; see Book and create at a location. A booking that would not fit a listed resource, or the default one, is 400 resource_too_small, and an unknown resource 404 resource_not_found.

POST /v1/resources creates a shared resource: a name, a capacity, and optionally the service_ids that draw on it. A linked service that can ask for more units than capacity is 400 capacity_below_service_requirement; a service booked by the day or night, or without a duration, is 400 invalid_parameter. A resource with no linked service limits nothing until one is linked to it.

For several services that compete for the same units — three wash basins shared by every treatment — create the resource first, then each service with resource_ids.

Both creates require Idempotency-Key, as does POST /v1/closures. Without one, a create retried after a lost response makes a second service, and the assistant offers callers both. Retry with the same key and the same body.

The two share a budget of 20 creations per minute with tag and caller-rule creates, on top of the write limit; pace a bulk set-up. See Errors and rate limits.

Services booked by the day or night, resources made of sized units such as tables or rooms, party sizes, buffers and exclusions are set up in Talki.

To stop the assistant offering a service, send PATCH /v1/services/{service_id} with is_active: false. Its bookings are kept, and is_active: true brings it back.

DELETE /v1/services/{service_id} deletes a service for good. Its own resource (owner_service_id) is deleted with it, and it stops drawing on every other resource. While any of its bookings is still to come or under way, the delete is refused with 409 service_has_upcoming_bookings, even on an inactive service: switch it off instead, and delete it once its last booking has ended or been cancelled. Past and cancelled bookings stay, with service.id null and the service name they were booked under.

DELETE /v1/resources/{resource_id} deletes a resource with its unit classes and service links. It is refused for the default resource (409 resource_is_default), and for the only resource of an active service, or of a service booked by the day or night even while inactive (409 resource_required_by_service). A booking that held one of its units keeps its time and loses the unit.

Nothing is cancelled or unlinked to let a delete through; see Delete refusals. Send an Idempotency-Key on both: without it, a retried DELETE that had already succeeded answers 404.

Once the business has dealt with an unresolved request, the next caller is likely to ask the same question. POST /v1/unresolved_requests/{request_id}/teach adds a general answer to a FAQ note the assistant uses with every caller:

Terminal window
curl --fail-with-body -X POST \
https://api.talki.it/v1/unresolved_requests/6c1f9a74-1d0b-4c8e-9a3d-2f5b7e0c4d13/teach \
-H "Authorization: Bearer $TALKI_API_KEY" \
-H "Idempotency-Key: teach-bridal-sundays" \
-H "Content-Type: application/json" \
--data '{"question":"Do you do bridal hair on Sundays?","answer":"Yes, on the first Sunday of each month, by appointment only."}'
  • It needs knowledge:write, an opt-in scope that unresolved:write does not include; see Scopes.
  • Only a resolved request can be taught from. Resolve it first with PATCH /v1/unresolved_requests/{request_id} and status: "resolved"; otherwise the answer is 409 unresolved_request_not_resolved.
  • Write question and answer for any caller, as the business would say them. They are not the request’s answer, which records what one caller was told and is neither read nor changed here.
  • location_id says where the assistant uses the answer: omit it for the request’s own location, send another location’s id, or send all for every location. An account whose multi_sede is false has one FAQ, used at every location, whichever of its locations you name. An id that is not one of the account’s locations is a 404, as is an unknown request. question takes up to 200 characters and answer up to 500, each counted after line breaks and repeated spaces become one space.
  • Idempotency-Key is required. Teaching the same request again adds another entry.
  • The 202 comes before the note is indexed: the assistant uses the answer shortly after, not necessarily on the very next call.

The FAQ is a note the business sees in Talki, «Domande frequenti» under Documenti, one per location; an answer taught with location_id all goes into each location’s note. The business can reword or delete what you taught, and nothing asks for its approval first: you are writing on the owner’s behalf, so agree with the business what to teach. A note that has no room left for the entry is refused with 409 faq_full, until the business tidies it in Talki; an account whose knowledge storage is full for its plan, with 413 payload_too_large.

The FAQ note is a document like any other: GET /v1/documents?faq=true lists it, and teaching sends document.created for a note it starts and document.updated for one it adds to, under knowledge:read. See Manage the knowledge base. The request comes back through its change feed with no published field changed.

These events report a change, whoever made it — the owner in Talki, or a credential through the API:

Event When data.object
account.updated A writable field of the account, onboarding_completed or phone_number changes Account
working_hours.updated The weekly hours change WorkingHours
closure.created, closure.updated, closure.deleted A closure or special opening is added, changed or removed Closure
service.created, service.updated, service.deleted A service is added, changed, switched off or on, or deleted Service
resource.created, resource.updated, resource.deleted A resource is added, changed, gains or loses a service, or is deleted Resource

A location other than the main one reports its own settings and hours with location.settings_updated and location.working_hours_updated; see Work with locations.

The account, hours and closure events need account:read, the service events services:read and the resource events resources:read. Receive them as a webhook or as app events. A save that changes none of the published fields of the account, the hours or a closure sends nothing.

Your own writes come back as events too. Drop those whose origin.source is api and whose origin.credential_id is your credential: the API key’s ID, or for an app the installation’s ID.

Replace your copy with data.object. Account and WorkingHours carry no timestamp, and a Closure only its created_at, which a change does not move. Events can arrive out of order, so keep the envelope created_at of the last event you applied to each object and skip an older one. A Service or Resource carries updated_at: order its events by that.

closure.deleted, service.deleted and resource.deleted carry the object as it was, and an ID seen deleted does not come back. A write to the catalogue sends an event for each service or resource it changed in passing too; see the event catalogue.