TXTImpact can tell your system, over HTTPS, when a contact taps a link in a text you sent. Every link you put in a message with the %URL{…}% tag is shortened to a tracked link that is unique to that message and recipient; the first time the recipient taps it, a link click webhook is sent to your endpoint.
When is a link-click webhook fired?
A link-click webhook fires once per link, on the first tap by a person:
- Each recipient of a message gets their own tracked link, so "once per link" means once per contact per message.
- Further taps on the same link are still redirected and still counted in your link statistics, but no second webhook is sent.
- Opens by link scanners, security filters and chat-app link previews (for example
facebookexternalhit,WhatsApp,Slackbot,curl) are ignored. A scanner that presents itself as an ordinary browser cannot be told apart from a person. - Only links sent inside a message fire. A short link you copied from the dashboard and shared elsewhere is not tied to a recipient, so it redirects as normal but sends no webhook.
Webhooks are dispatched by a background job that runs every 30 seconds, so expect the request within about a minute of the tap.
Configuration
Configure link-click webhooks in the TXTImpact dashboard under Integrations → Delivery Reports → Link clicks:
- Press Add webhook.
- Choose which links it covers: Any link in a text you send, or A specific link — the address exactly as you put it in the message, before it was shortened. Matching ignores letter case and a trailing slash.
- Enter the endpoint to send to (HTTPS recommended) and save.
You can add several webhooks — for example one endpoint for every link and another for one campaign's landing page. Each matching webhook receives its own request. A webhook can be switched off without deleting it.
A tap can also start a workflow: open the workflow, click its trigger and add a trigger of type When a link is clicked. That is configured in the workflow builder and does not involve a webhook.
Authentication (X-W2A-Token header)
To prove the request originated from TXTImpact, set a shared secret under Integrations → Webhook Settings. TXTImpact sends it back on every webhook request — link clicks, delivery reports and inbound messages alike — as:
X-W2A-Token: <your-secret>
Your endpoint should reject any request whose X-W2A-Token header does not match your stored copy. If no token is saved, the header is not sent.
HTTP request format
Method
POST
Content Type
application/json; charset=utf-8
Headers
| Header | Notes |
|---|---|
Content-Type | application/json |
X-W2A-Token | Shared-secret echo (see Authentication above); absent when no token is saved |
Sample JSON Body
{
"event": "link.clicked",
"originalUrl": "https://www.example.com/fall-offer",
"shortCode": "4q4zJQ",
"mobileNumber": "12125550142",
"messageId": "af8d84df7e1d436d89e00a47815410c2",
"clickedAt": "2026-10-08T14:57:32Z",
"occurredAt": "2026-10-08T14:57:32Z"
}
Field Definitions
| JSON Field | Type | Notes |
|---|---|---|
event | string | Always link.clicked. Lets one endpoint handle several TXTImpact webhook types. |
originalUrl | string | The address as you wrote it in the message, before shortening. Use it to tell which link or campaign was tapped. |
shortCode | string | The code at the end of the shortened link the contact tapped. Unique to that recipient and message, so it works as an idempotency key. |
mobileNumber | string | The contact's phone number (E.164 digits, no +). Omitted when the link was not sent to one person (a shared link). |
messageId | string | Identifier of the message the link was sent in — the same messageId returned when you submitted the send and carried by its delivery report, so a click can be matched to the message and its delivery status. Omitted for a shared link. |
clickedAt | string | When the link was tapped, ISO-8601 UTC (YYYY-MM-DDTHH:MM:SSZ). |
occurredAt | string | Same instant as clickedAt; present on every TXTImpact event type under this name. |
Notes:
- Fields with no value are omitted from the body rather than sent as
null— check for presence. - The message text is intentionally not included; correlate with
messageId.
Expected Response & Retry Policy
Your endpoint must respond with a 2xx HTTP status within 30 seconds. Any non-2xx, timeout, or transport-level failure triggers an automatic retry on the schedule below:
| Attempt | Wait before next try |
|---|---|
| 1 (initial) | 30 seconds |
| 2 | 2 minutes |
| 3 | 10 minutes |
| 4 | 30 minutes |
| 5 | 1 hour |
| 6 | 3 hours |
| 7 | terminal — no further retries |
Total retry window is about 5 hours over 7 attempts. After that the request is marked permanently failed.
Recommended Implementation Notes
- Treat all fields as strings and parse defensively.
- Use
shortCodeas your idempotency key — TXTImpact may retry the same webhook if your endpoint returned a transient error. Persist the first successful processing and ignore duplicates. - Validate the
X-W2A-Tokenheader on every request; reject unauthorized payloads with401. - Respond with
200 OKas quickly as possible. Defer any heavy processing to a background worker so you don't hit the 30-second timeout. - Branch on
eventif the same endpoint also receives delivery reports or inbound messages.