Your shop or CRM knows things about customers that Soosh doesn’t, and Soosh learns things in chats that your system doesn’t. This guide keeps the two lists matched both ways: you push your changes to Soosh, and you pull Soosh’s changes back.
Before you start
Section titled “Before you start”- An API key that can List and read contacts (
contacts:read) and Create, change and delete contacts and tags (contacts:write) - Optional: a webhook endpoint for
contact.created,contact.updatedandcontact.deleted
Match customers by phone number. Soosh keeps one contact per WhatsApp
number, and finds it whichever way you write the number: with or without
+, spaces or dashes, and with 00 for +. Mexican and Argentine mobiles
match however WhatsApp writes them (with or without the 1 after 52, or the
9 after 54).
1. Push a new customer
Section titled “1. Push a new customer”Create the contact with an
Idempotency-Key, so a retry never makes two:
curl https://app.soosh.io/v1/contacts \ -H "Authorization: Bearer $SOOSH_API_KEY" \ -H "Idempotency-Key: customer-8812" \ -H "Content-Type: application/json" \ -d '{ "phone": "+91 98765 43210", "name": "Priya Sharma", "attributes": { "customer_id": "8812", "city": "Pune", "orders": 3 }, "tags": ["VIP"] }'You get 201 and the Contact. Save its
id next to your customer.
If Soosh already has a contact with that number, for example because Priya
wrote to you first, you get 409 conflict
and error.details.id is that contact. Save that id, then change the contact as in step 2. A contact
deleted earlier is brought back instead, with its history, and that’s a
201 too.
To find a contact by number at any time:
curl "https://app.soosh.io/v1/contacts?phone=%2B919876543210" \ -H "Authorization: Bearer $SOOSH_API_KEY"2. Push changes
Section titled “2. Push changes”Update a contact with only the fields that changed:
curl -X PATCH https://app.soosh.io/v1/contacts/$CONTACT_ID \ -H "Authorization: Bearer $SOOSH_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "attributes": { "city": "Mumbai", "orders": 4, "old_field": null } }'- Attributes are merged. Keys you leave out stay. A key set to
nullis removed. A contact has at most 50. A name is 1 to 64 letters, digits or underscores and can’t start with__. A text value is at most 1,024 characters. - The name is yours once you set it. A name you set over the API (or in
the app) isn’t replaced by the customer’s WhatsApp profile name. That one
stays in
whatsapp_name. Send"name": ""to go back to the WhatsApp name. - Tags have their own requests.
PUT /v1/contacts/{id}/tags/{tag}adds one andDELETEremoves it. Both are safe to repeat. A contact has at most 50 tags. - Opt-outs: set
marketing_opt_outtotruewhen a customer tells you they don’t want marketing messages. Soosh then leaves them out of marketing broadcasts and refuses marketing templates to them.
When you delete a customer in your system, delete the contact:
DELETE /v1/contacts/{id}.
3. Pull changes made in Soosh
Section titled “3. Pull changes made in Soosh”Customers write in, agents edit names and tags, and imports add contacts. Pick up those changes in one of two ways, or both.
With webhooks, as they happen
Section titled “With webhooks, as they happen”Subscribe an endpoint to these events. Each event comes in the envelope. See Verify webhooks to check each one.
| Event | Sent when | What to do |
|---|---|---|
contact.created |
A contact is added, however it came in | Add the customer, or link it to yours by phone. |
contact.updated |
The name, attributes, tags, opt-out or number changed | data.changed lists the fields. Copy them from data.contact. |
contact.deleted |
A contact is deleted | Unlink or delete your customer. data has contact_id and phone. |
Events can arrive out of order. Compare updated_at with what you have, and
skip an older one.
By asking, to catch up
Section titled “By asking, to catch up”List contacts by when they changed, oldest change first (see Pagination):
curl "https://app.soosh.io/v1/contacts?sort=updated_at&limit=100" \ -H "Authorization: Bearer $SOOSH_API_KEY"- Save each contact.
- If
next_cursorisn’tnull, ask again withcursorset to it. - When
next_cursorisnull, you’re up to date. Save theupdated_atof the last contact you got. - Next time, start with
updated_afterset to a minute before that time, and skip contacts whoseupdated_atyou already have. A contact that changed since has moved to the end of the list, so you get it again.
The list shows a change about 30 seconds after it’s saved. A change that is still being saved can carry an earlier time than one already listed; the wait lets almost all of them land first, and going back a minute catches the rest. A contact you just changed shows up about half a minute later.
To start over from a time instead, send updated_after, like
updated_after=2026-10-15T00:00:00Z.
Result
Section titled “Result”New customers and changes flow both ways. Your system and Soosh agree on each customer, matched by phone number, with no duplicates.