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.
Business information and instructions
Section titled “Business information and instructions”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.
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."}'Other assistant settings
Section titled “Other assistant settings”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_openingneeds a plan that includes a custom opening, or the write is refused with403 plan_feature_unavailable. Clearing it is allowed on every plan.store_transcripts: falsedeletes every transcript already stored, at once and for good. A test-mode credential sending it is refused with409 livemode_required.transfer_numbersreplaces the whole list. An empty list needs nothing else. A non-empty one needs aforwarding_number, stored or sent in the same request, and none of its numbers may equal it. Eachlabelis 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_numberis held to the same rule from the other side: it cannot equal one of thetransfer_numbers, and cannot be cleared while the list has entries, unless the same request replaces the list.notify_on_every_callandnotify_on_incoming_callcontrol 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 oncall.endedorappointment.created.call_auto_archive_daysis the account’s own setting, the same at every location. Send it withoutlocation_id, or with the main location’s: with another location’s, the request is refused with400 invalid_parameter. The nightly archiving sendscall.updatedfor each call, withorigin.sourcesystem.languagesis read only: every call opens inprimary(it), and the assistant can switch to any language insupported.multilingual_enabledis what changes it.
Call forwarding
Section titled “Call forwarding”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.
Weekly hours
Section titled “Weekly hours”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" } ]}endmust be afterstart, so a range cannot cross midnight: send two slots, one ending at23:59and one starting at00:00on 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.
Closures
Section titled “Closures”A closure is a dated exception to the weekly hours, in one of two forms:
- whole days:
all_day: truewithstart_dateandend_date, both included; - an exact range:
start_atandend_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”.
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.
Concurrent edits: ETag and If-Match
Section titled “Concurrent edits: ETag and If-Match”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/accountcan write. A change tophone_numberoronboarding_completeddoes not move it. - A write that asks for exactly what is already stored succeeds whatever
If-Matchsays. 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
412is not stored against the request’sIdempotency-Key, so the retry with the fresh tag can reuse the same key. - A response replayed from an
Idempotency-Keycarries noETag. Read again for a current one.
Tags are opaque: store them as strings and do not parse them.
Create services and resources
Section titled “Create services and resources”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 itsowner_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.
Delete services and resources
Section titled “Delete services and resources”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.
Teach the assistant an answer
Section titled “Teach the assistant an answer”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:
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 thatunresolved:writedoes not include; see Scopes. - Only a
resolvedrequest can be taught from. Resolve it first withPATCH /v1/unresolved_requests/{request_id}andstatus: "resolved"; otherwise the answer is409 unresolved_request_not_resolved. - Write
questionandanswerfor any caller, as the business would say them. They are not the request’sanswer, which records what one caller was told and is neither read nor changed here. location_idsays where the assistant uses the answer: omit it for the request’s own location, send another location’s id, or sendallfor every location. An account whosemulti_sedeisfalsehas 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.questiontakes up to 200 characters andanswerup to 500, each counted after line breaks and repeated spaces become one space.Idempotency-Keyis required. Teaching the same request again adds another entry.- The
202comes 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.
Keep a copy in sync
Section titled “Keep a copy in sync”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.
