Custom CRM
For a CRM we don't integrate with out of the box — an in-house system, clinic software, anything your team built. When a deal moves to a new stage, your CRM sends one HTTPS request with the customer's phone number and the stage name. AdsPing does the rest.
How it works
A customer clicks your Click-to-WhatsApp ad and messages you. AdsPing records that conversation together with the ad click. Later, your team moves the customer's deal through your CRM — for example from Appointment booked to Closed Won. Each move, your CRM posts the phone number and the new stage to AdsPing. AdsPing finds the conversation by phone number, attaches the ad click, and sends the conversion to Meta. Meta learns which ads bring paying customers, not just messages.
Your CRM never stores cookies, pixel IDs or ad click IDs. A phone number and a stage name are enough.
Get your webhook URL
Account owner · Integrations → WhatsApp.
Open your pixel → Integrations → WhatsApp. Under Feed conversions back from your CRM, click Create webhook endpoint and copy the Webhook URL. Send it to your developer privately — the key at the end of the URL works like a password.
This card appears once a WhatsApp number is connected. It is hidden when Pipedrive or another built-in CRM is connected to the same pixel, because that CRM already decides which stages to send.
Build the request
Developer · one POST per stage change.
Whenever a deal changes stage, your CRM's server sends the request in the developer reference below. Send every stage change — AdsPing ignores the stages you haven't mapped, so the CRM doesn't need to filter.
Map your stages
Account owner · the same WhatsApp card.
Ask your developer for the exact stage names the CRM sends. For each one that matters, click Add row, type the stage name exactly as the CRM spells it, and pick the event:
- Lead — a new inquiry. Skip it if every WhatsApp message already counts as a lead.
- Qualified lead — booked an appointment, showed up, passed your sales team's check.
- Purchase — paid. Turn on Optimization here so Meta optimizes for paying customers.
Click Save mapping. Stages you don't map, such as Lost, are never sent.
Test it
Message your own number, then move a deal.
Message your WhatsApp number from a test phone, create a deal for that number in your CRM, and move it to a mapped stage. The response should say processed: 1, and within about a minute the event shows up in your WhatsApp activity in AdsPing. A test message doesn't come from an ad, so it carries no ad click — that link appears with real ad conversations.
Developer reference
POST https://api.adsping.io/api/v1/webhooks/feedback/YOUR_KEY
Content-Type: application/jsonNo other headers or authentication. Keep the URL in a server-side environment variable — never in browser code, git, or logs.
| Field | Type | Required | Description |
|---|---|---|---|
phone | string | yes | The customer's WhatsApp number with country code, e.g. 15551234567 or +1 555 123 4567. |
stage | string | yes | The deal's new stage name, spelled exactly as in the CRM. |
value | number | on sales | Deal amount as a number, e.g. 1200. |
currency | string | with value | ISO 4217 code: USD, EUR, TRY… |
externalId | string | no | Your CRM deal ID. |
email | string | no | Improves match quality. |
firstName, lastName | string | no | Improves match quality. |
city, country | string | no | e.g. Austin, US. |
curl -X POST 'https://api.adsping.io/api/v1/webhooks/feedback/YOUR_KEY' \
-H 'Content-Type: application/json' \
-d '{
"phone": "15551234567",
"stage": "Closed Won",
"value": 1200,
"currency": "USD",
"externalId": "deal-4821",
"firstName": "Jane",
"lastName": "Doe",
"country": "US"
}'Responses
A valid request returns HTTP 200 with the outcome inside data, e.g. {"success":true,"data":{"received":true,"processed":1}}. Log data.reason. HTTP 400 means the body is malformed — an empty stage, or a value that isn't a number.
| data | Meaning |
|---|---|
processed: 1 | Accepted; sent to Meta within about a minute. |
reason: "lead_not_found" | No WhatsApp conversation with this number — the person never messaged the connected number, or the phone format doesn't match. |
reason: "no_mapping" | This stage isn't mapped in AdsPing; ignored on purpose. |
reason: "duplicate" | This number already reached this stage; ignored. |
reason: "unknown_key" | The key in the URL is wrong. |
reason: "missing_identity" | No phone number in the body. |
None of these reasons are errors — don't retry them. Until setup is finished, lead_not_found and no_mapping are expected.
Rules
- Phone format matters most. Matching uses the number's digits exactly as WhatsApp reports them: country code first, no leading 0. Spaces,
+and dashes are fine. A national number such as05321234567won't match — add the country code before sending. - Keep stage names stable. They are matched exactly, including case and accents. Tell the account owner before renaming a stage, or send a fixed stage code instead of the display name.
- Send right away, in the background. Send when the stage changes, from a queue or background job, so moving a deal never waits on AdsPing. Don't batch old deals.
- Retry only on network errors, timeouts and 5xx — up to 3 times with the same body (1 min, 5 min, 30 min). A request that arrives twice is harmless.
- No phone, no request.