Contact webhooks
Push new leads and contacts into Superpractice from intake forms, CRMs, Zapier, and any other system that can send an HTTPS request.
Overview
The contact webhook gives you a personal endpoint URL that creates contacts in Superpractice. Point an intake form, your CRM, Zapier, or any custom system at the URL and every valid payload becomes a contact, ready for follow-up, lead scoring, and attribution.
It is the simplest way to capture leads from tools Superpractice does not integrate with directly. If a matching contact already exists, the webhook updates it instead of creating a duplicate.
https://app.superpractice.com/api/webhooks/contacts/{webhook_token}Setup
- Open Settings > Integrations and find the Contact Webhook card.
- Connect it to generate your endpoint URL. Treat the URL as a secret, because the token in the path authenticates the sender.
- Capture a test payload: start a test in the card, then send one real webhook from the source system.
- Map each incoming JSON field to a Superpractice contact field. Nested paths like
lead.email_addressare supported, and you can choose "Always use" constants for fields with fixed values. - Save the mappings, then send a live webhook and confirm the contact appears in Superpractice.
If you skip field mapping, the payload must already use the Superpractice field names shown below.
Request basics
Send an HTTPS POST request with a JSON body and the Content-Type: application/json header. The 64-character token in the URL is the only authentication needed.
- Health check: a
GETto the same URL verifies the token is active without creating anything. - Rate limit: 120 requests per hour by default (configurable). Requests over the limit return
429. - Validation: every contact needs at least one valid email or phone number, otherwise the request returns
400. - Errors: failed requests are logged, and the most recent error is shown on the Contact Webhook card in Settings.
Field reference
These are the Superpractice contact fields after mapping is applied.
| Field | Required | Notes |
|---|---|---|
email or phone | Yes | At least one valid email or phone is required. E.164 phone format is recommended, for example +15550100000. |
sourceSystem | No | Identifies the sender, for example intake_form. Defaults to custom_webhook when unmapped. |
externalContactId | No | Optional stable ID from the sender. Strongly recommended, because it gives the most reliable deduplication. |
fullName | No | A single name field. Superpractice splits it into first and last name automatically. Explicit firstName and lastName values override the split. |
firstName | No | First name. Takes priority over the split from fullName. |
lastName | No | Last name. Takes priority over the split from fullName. |
practiceArea | No | The practice area the lead is asking about. |
notes | No | Free-text notes stored on the contact, for example the message from an intake form. |
utmSource / utmMedium / utmCampaign / utmContent / utmTerm | No | Optional marketing attribution for the touch this submission represents. Applies to both first and last touch unless the per-touch fields below are provided. Raw values are retained and also normalized into Superpractice's standard channels — see Attribution values. |
landingPage / referrer | No | The page the lead converted on and the referring URL, when the sender has them. |
gclid / fbclid / msclkid | No | Ad click IDs. When present, Superpractice can infer the paid channel even if utmSource is missing. |
firstTouchSource / firstTouchMedium / firstTouchCampaign / firstTouchContent / firstTouchTerm / firstTouchLandingPage / firstTouchReferrer / firstTouchGclid / firstTouchFbclid / firstTouchMsclkid / firstTouchTimestamp | No | Explicit first-touch attribution — how the contact originally found the firm. Overrides the generic attribution fields for the first touch. firstTouchTimestamp accepts ISO date/time and defaults to receipt time. Ideal for CRMs pushing leads with known history. |
lastTouchSource / lastTouchMedium / ... / lastTouchTimestamp | No | Explicit last-touch attribution — the most recent touch before this submission. Same field set as first touch. When only one side is provided, the other mirrors it on creation. |
Attribution values Superpractice accepts
You can send any source and medium strings — Superpractice keeps the raw values for auditing and also normalizes them into canonical channels used across dashboards, reports, and notifications. Common aliases resolve automatically (for example google + cpc, adwords, and googleads all normalize to google-ads). If a gclid, fbclid, or msclkid is present, the paid channel is inferred even when the source is missing.
To guarantee exact bucketing, send these canonical source values verbatim:
| Channel group | Canonical sources |
|---|---|
| Paid search & LSA | google-ads, google-lsa, bing-ads, paid-search |
| Paid social & display | facebook-ads, instagram-ads, linkedin-ads, tiktok-ads, twitter-ads, youtube-ads, paid-social, display, programmatic, retargeting |
| Organic search | google-organic, bing-organic, yahoo-organic, brave-organic, duckduckgo, organic-search |
| Organic social | facebook-organic, instagram-organic, linkedin-organic, tiktok-organic, twitter-organic, youtube-organic, organic-social |
| Google profile | google-business, google-reviews |
| Legal directories | avvo, findlaw, justia, lawyers.com, martindale, nolo, superlawyers, yelp |
| AI assistants | chatgpt, perplexity, gemini, claude, copilot, openai, xai, deepseek, mistral |
| Everything else | direct, referral, affiliate, phone, booking-widget, billboard. Unrecognized domains (for example examplepartner.com) are kept as referral sources. |
Canonical medium values: cpc, cpm, display, organic, paidsocial, social, referral, retargeting, affiliate, email, offline, call, scheduling. Medium is optional — when omitted, Superpractice infers a sensible default from the source.
How touches are applied: when the webhook creates a contact, the first and last touch are written from your payload (mirrored if you only send one side), using your timestamps when provided. When a submission matches an existing contact, it counts as a new touch — the last touch updates, and the first touch is only filled if the contact has none recorded. Existing first-touch data is never overwritten.
Deduplication
Before creating a contact, Superpractice looks for an existing match in this order:
externalContactIdfor the samesourceSystem- Phone number
- Email address
When a match is found, the existing contact is updated rather than duplicated. Updates fill in missing fields but do not overwrite values the contact already has. The response tells you which action was taken via "action": "created" or "action": "updated".
Minimal payload
If the sender already uses Superpractice field names, no mapping is needed.
curl -X POST "https://app.superpractice.com/api/webhooks/contacts/{webhook_token}" \
-H "Content-Type: application/json" \
--data '{
"sourceSystem": "intake_form",
"fullName": "Jane Public",
"email": "jane@example.com",
"phone": "+15550100000"
}'Custom payloads
The sender does not have to match Superpractice field names. Capture the real payload in the settings card, then map each incoming path to a contact field. Nested paths work.
curl -X POST "https://app.superpractice.com/api/webhooks/contacts/{webhook_token}" \
-H "Content-Type: application/json" \
--data '{
"lead": {
"id": "lead_example_001",
"name": "Jane Public",
"email_address": "jane@example.com",
"phone_number": "+15550100000"
},
"form": {
"practice_area": "Estate Planning",
"message": "Interested in a consultation."
}
}'In this example, map lead.id to External Contact ID, lead.name to Full Name, lead.email_address to Email, lead.phone_number to Phone, form.practice_area to Practice Area, and form.message to Notes. You could also set Source System to an "Always use" constant like website_intake.
Responses
A successful request returns the action taken and the contact ID.
{
"success": true,
"action": "created",
"contactId": "00000000-0000-0000-0000-000000000000",
"warnings": []
}Common error responses:
400invalid JSON, or no valid email or phone after mapping.401invalid or inactive webhook token.429rate limit exceeded (120 requests per hour by default).
The last error is also shown on the Contact Webhook card in Settings > Integrations, which is the fastest place to check when a sender reports failures.
Which webhook should I use?
Contact Webhook
General contact and lead intake for your firm. One endpoint per user, with field mapping for any payload shape. Use it for intake forms, CRMs, and automation tools.
Matter Webhook
Retained and open matters with amounts, stages, and service line items from case management systems. Use it when the event is a matter, not just a lead. See Matter webhooks.
Agent Lead Webhook
Wired to a specific AI calling agent so a new lead triggers an immediate outbound dial. Use it when speed-to-lead matters more than general intake.
Notifications
Contacts created by the webhook get the source contact_webhook and can trigger the per-user New Contact email and SMS alerts. Turn those on in Settings > Notifications if you want to be pinged the moment a lead arrives.