REST API v1 · Resource
Contacts
Create, update, upsert in bulk, tag, block and delete contacts, and read your tags and custom fields.
API reference · Contacts
Endpoints
Paths are relative to https://fliok.com/api/v1. Each endpoint names the scope and the lowest key role it needs; a key without them gets 403 (see Authentication).
Contacts
10- POST
/contactsCreate a contactScopecontacts:write· agent role or higherNeeds an API key - GET
/contacts/{id}Get one contact with its custom fields — by our id or by phone numberScopecontacts:read· viewer role or higherNeeds an API key - PATCH
/contacts/{id}Update a contact. Custom attributes merge rather than replaceScopecontacts:write· agent role or higherNeeds an API key - DELETE
/contacts/{id}Delete a contactScopecontacts:delete· admin role or higherNeeds an API key - POST
/contacts/bulkCreate or update up to 500 contacts in one call, each by the POST /contacts rules. New ones count against the plan; answers per rowScopecontacts:write· agent role or higherNeeds an API key - POST
/contacts/bulk-tagsAdd and remove tags on up to 500 contacts, by id or phone number. Unknown ones are named backScopecontacts:write· agent role or higherNeeds an API key - POST
/contacts/{id}/blockBlock the customer on WhatsApp (only within 24 hours of their last message — WhatsApp’s rule)Scopecontacts:write· agent role or higherNeeds an API key - POST
/contacts/{id}/unblockLift a WhatsApp blockScopecontacts:write· agent role or higherNeeds an API key - GET
/tagsEvery tag on your contacts with how many carry itScopecontacts:read· viewer role or higherNeeds an API key - GET
/contact-fieldsYour custom contact fields: the key inside attributes, label, type and choicesScopecontacts:read· viewer role or higherNeeds an API key
Request bodies
What these endpoints take, field by field. A body that doesn’t match answers 400 naming the field.
GET /messages · GET /contacts · GET /conversations
Query parameters. Newest first; pass the previous page’s nextCursor as cursor until it comes back null. /messages and /contacts page by creation, so a sync never skips a row; /conversations orders by latest activity, so a chat that gets a message while you page can move — sync with /messages instead.
| Field | Type | What it is |
|---|---|---|
limit | number | 1–100, default 50. |
cursor | uuid | The nextCursor of the page before. Anything else is a 400. |
conversationId | uuid | /messages only: one chat’s messages. |
status | string | /messages only: queued, sent, delivered, read, failed or skipped. |
search | string | /contacts only: part of a number, a name or a WhatsApp username. |
channel | string | /contacts only: "instagram" lists Instagram customers (their e164 is "ig:<id>", not a phone). |
Returns 200 { "messages" | "contacts" | "conversations": [ … ], "nextCursor": "<uuid>" | null }. Every contact carries `userId` (their WhatsApp user id) and `username` (their WhatsApp username), null when WhatsApp has sent us neither. A WhatsApp customer whose number is not shared has "wa:<user id>" as e164. An Instagram customer also carries `instagram`: { "igsid", "username" } (null for everyone else).
POST /contacts · PATCH /contacts/{id}
JSON body. POST is keyed by phone: a number you already have is updated (200), a new one is created (201) and counts toward your contact limit. {id} is our id, the phone number, or — for a customer WhatsApp shares no number for — the "wa:<user id>" we report as their e164. Such a contact is created when they write to you, never by POST.
| Field | Type | What it is |
|---|---|---|
phonerequired | string | POST only (or "e164"). E.164, with or without “+”. |
displayName | string | Up to 200 characters. |
tags | string[] | Up to 50 tags, replacing the current ones. |
attributes | object | Custom fields. Merged into what is stored, never replacing it. |
optInStatus | string | unknown, opted_in or opted_out. A contact who sent STOP can’t be opted back in by the API (409). |
optInSource | string | Where the consent came from, up to 120 characters. |
Returns POST → 201 { "contact": { … }, "created": true } (200 with false for a known number). PATCH → 200 { "contact": { … } }
Rate limits
The buckets these endpoints use. Burst is how many requests you can make back-to-back from a full bucket; sustained is how fast it refills.
| Bucket | Endpoints | Burst | Sustained |
|---|---|---|---|
| Reads | /messages · /conversations · /contacts · /templates · /phone-numbers · GET /webhooks · Instagram reads · GET /payment-requests/{id} | 600 | 60 / sec |
| Contact writes | POST /contacts · PATCH /contacts/{id} | 120 | 10 / sec |
| Contact erasure | DELETE /contacts/{id} | 20 | 1 / 3 sec |
Every limit, the RateLimit-* headers and what to do on a 429: Rate limits.