®Docs

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.

Endpoint format
https://app.superpractice.com/api/webhooks/contacts/{webhook_token}

Setup

  1. Open Settings > Integrations and find the Contact Webhook card.
  2. Connect it to generate your endpoint URL. Treat the URL as a secret, because the token in the path authenticates the sender.
  3. Capture a test payload: start a test in the card, then send one real webhook from the source system.
  4. Map each incoming JSON field to a Superpractice contact field. Nested paths like lead.email_address are supported, and you can choose "Always use" constants for fields with fixed values.
  5. 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 GET to 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.

FieldRequiredNotes
email or phoneYesAt least one valid email or phone is required. E.164 phone format is recommended, for example +15550100000.
sourceSystemNoIdentifies the sender, for example intake_form. Defaults to custom_webhook when unmapped.
externalContactIdNoOptional stable ID from the sender. Strongly recommended, because it gives the most reliable deduplication.
fullNameNoA single name field. Superpractice splits it into first and last name automatically. Explicit firstName and lastName values override the split.
firstNameNoFirst name. Takes priority over the split from fullName.
lastNameNoLast name. Takes priority over the split from fullName.
practiceAreaNoThe practice area the lead is asking about.
notesNoFree-text notes stored on the contact, for example the message from an intake form.
utmSource / utmMedium / utmCampaign / utmContent / utmTermNoOptional 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 / referrerNoThe page the lead converted on and the referring URL, when the sender has them.
gclid / fbclid / msclkidNoAd 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 / firstTouchTimestampNoExplicit 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 / ... / lastTouchTimestampNoExplicit 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 groupCanonical sources
Paid search & LSAgoogle-ads, google-lsa, bing-ads, paid-search
Paid social & displayfacebook-ads, instagram-ads, linkedin-ads, tiktok-ads, twitter-ads, youtube-ads, paid-social, display, programmatic, retargeting
Organic searchgoogle-organic, bing-organic, yahoo-organic, brave-organic, duckduckgo, organic-search
Organic socialfacebook-organic, instagram-organic, linkedin-organic, tiktok-organic, twitter-organic, youtube-organic, organic-social
Google profilegoogle-business, google-reviews
Legal directoriesavvo, findlaw, justia, lawyers.com, martindale, nolo, superlawyers, yelp
AI assistantschatgpt, perplexity, gemini, claude, copilot, openai, xai, deepseek, mistral
Everything elsedirect, 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:

  1. externalContactId for the same sourceSystem
  2. Phone number
  3. 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
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
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:

  • 400 invalid JSON, or no valid email or phone after mapping.
  • 401 invalid or inactive webhook token.
  • 429 rate 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.

On this page