The Tellfox API
The Tellfox API lets another system read and change a business’s customers, bookings, packages and loyalty, and be told when something happens. It is a yearly add-on on the Business and Pro plans (Plan & add-ons → Add-ons). Everything below is for the developer who builds the connection.
- Base address:
https://api.tellfox.app/v1 - Format: JSON in and out, UTF-8. Times in UTC (ISO 8601). Money in satang: whole numbers, 1 baht = 100 satang.
- Machine-readable spec: OpenAPI 3.1, made from the same table the API runs on.
An owner makes keys on Settings → API in the Tellfox owner pages. Each key has:
- a name (“Shop POS”): the activity feed shows it on everything the key does (“Shop POS gave a stamp”);
- a system name (
pos,crm): your system’s own customer IDs are kept under it (external_id); - scopes: what it may do (
customers:read,customers:write,bookings:read,packages:write,loyalty:write,payments:read, …). A write scope also reads. Every key can read the business, its branches, services and team; - optionally, branches: then it sees and changes only bookings, services and team of those branches.
The secret is shown once. Tellfox keeps only a hash of it. Send it in every call:
curl https://api.tellfox.app/v1/business \ -H "Authorization: Bearer tfx_live_…"GET /v1/business answers the business, its branches and what the key may do: a good first call. A key that was revoked answers 401 key_revoked at once. When the add-on’s year ends, or the plan is no longer Business or Pro, every key answers 403 addon_required (nothing is deleted; the keys work again when it is renewed).
Test keys
Section titled “Test keys”A test key (tfx_test_…) works on a test copy of the business, made with the first test key: its branches, opening hours, team, services, rooms, packages, tags and loyalty program, but no customers or bookings. Nothing is ever sent to anyone from the test copy (no LINE messages, no emails). Try every call there first; the owner can make the copy again from the business as it is now (Make it again on Settings → API). The same code then works with a live key.
Answers and errors
Section titled “Answers and errors”A success answers {"data": …} (a list also has "meta": {"next_cursor": …}). A create answers 201. An error answers its status and:
{ "error": { "code": "invalid", "message": "Not a phone number.", "field": "query.phone", "request_id": "req_…" } }| Status | code |
What to do |
|---|---|---|
| 400 | bad_request, idempotency_key_required |
Fix the request (send JSON; send an Idempotency-Key with a write) |
| 401 | unauthorized, key_revoked |
Check the key |
| 403 | addon_required, scope_required, branch_forbidden |
The add-on is off, or the key may not do this |
| 404 | not_found |
No such thing in this business |
| 409 | conflict, idempotency_in_progress |
Look at the state, or retry a little later |
| 422 | invalid, plan_limit, idempotency_key_reused |
A value is wrong (field names it), or the plan allows no more |
| 429 | rate_limited, daily_limit |
Wait for Retry-After seconds |
| 500 | server_error |
Retry with the same Idempotency-Key |
Every answer has an X-Request-Id header: give it to Tellfox support when you ask about a call.
Limits
Section titled “Limits”- 60 calls a minute per key. Above it:
429 rate_limitedwithRetry-After. - 10,000 calls a day per business (UTC day; live and test keys are counted apart). Above it:
429 daily_limituntil tomorrow. - Lists answer at most 200 at a time (50 by default).
Lists answer a page and meta.next_cursor. Send it back as cursor for the next page; null means there is no more.
curl "https://api.tellfox.app/v1/customers?limit=100" -H "Authorization: Bearer $KEY"curl "https://api.tellfox.app/v1/customers?limit=100&cursor=WyIyMDI2…" -H "Authorization: Bearer $KEY"Keeping another system in step
Section titled “Keeping another system in step”GET /v1/customers and GET /v1/bookings?updated_since=… answer the oldest change first, with updated_at (UTC). To sync:
- Read every page once with
updated_since=1970-01-01T00:00:00Zand keep the largestupdated_atyou saw. (Withoutupdated_since, bookings are listed by start time from now on, which is for showing a calendar, not for a sync.) - Every few minutes, call again with
updated_sinceset to one minute before it, read every page, and keep the new largestupdated_at. The minute covers a change that was being saved while you read.
A customer’s updated_at moves with any change to the customer, their phone numbers and emails, tags, consent or IDs (their visit numbers follow the bookings instead); a booking’s with any change to it. You may see a row twice; you never miss one.
A customer the business erased on request (PDPA) is either anonymised (still listed, anonymised: true, name and contact details gone) or, when they had nothing else, deleted: read GET /v1/customers/erased with the same updated_since and delete your copy of those IDs.
To find one customer, use phone (any format: 081-234-5678 finds +66812345678), email, or your own external_id.
Writes and safe retries
Section titled “Writes and safe retries”Every write (POST, PATCH, DELETE) needs an Idempotency-Key header: text up to 255 characters that is unique for all time, for example a UUID, or the date with your own sale number. Sending the same request again with the same key does nothing twice and answers the first answer (with the header Idempotent-Replayed: true); the key is kept 24 hours. The same key with a different request answers 422 idempotency_key_reused.
Writes go through the same rules as the owner pages: the plan’s limits, a key limited to some branches, and the messages customers usually get. Amounts always come from Tellfox’s own prices, never from the request.
What stays in the owner pages
Section titled “What stays in the owner pages”Sending LINE messages and broadcasts, confirming and refunding payments, deleting customers, and changing the plan, team, opening hours, prices and settings are done in the owner pages, where a person decides.