Submitting Form Data to ContactDrive with a Webhook
The Webhooks app lets any external tool — a form builder, a landing page, a custom script, or an automation platform — send contacts straight into your ContactDrive workspace by making a single HTTP POST request. This guide walks through setting up an inbound webhook and sending a form submission using the flat contact format, which is the format webhooks expect.
What you'll need
- The Webhooks app installed in your workspace
- A ContactDrive API key for the workspace (Settings → API Keys)
- A tool or form that can send an HTTP
POSTrequest with a JSON body
Step 1 — Create an inbound webhook
- Open Apps → Webhooks and click Add Webhook.
- Choose Inbound as the webhook type.
- Fill in:
- Name — a label so you can recognize it later (e.g. "Newsletter signup form").
- Activity Type — the activity recorded against each contact that comes in through this webhook (e.g. "Form Submission"). Optional, but recommended.
- Description — optional notes.
- Tags — optional. Any tags you set here are automatically applied to every contact submitted through this webhook.
- Save the webhook.
After saving, open the webhook to find its Endpoint URL. It looks like this:
https://api.contactdrive.app/api/v2/webhooks/<aBc123XyZtoken>
The token at the end is unique to this webhook. Copy the full URL — that's where your form will send its data.
Step 2 — Send a POST request
Send an HTTP POST to your endpoint URL with:
- A
Content-Type: application/jsonheader - An Authorization header carrying your API key as a Bearer token
- A JSON body using the flat contact format (see below)
Example
curl -X POST "https://api.contactdrive.app/api/v2/webhooks/<aBc123XyZtoken>" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"firstName": "Jane",
"lastName": "Smith",
"workEmail": "jane.smith@example.com",
"mobilePhone": "555-0100",
"organization": "Acme Corp",
"jobTitle": "Operations Lead",
"homeCity": "Denver",
"homeState": "CO",
"homeZip": "80202",
"tags": "newsletter, lead",
"notes": "Signed up via the spring campaign form"
}'
The endpoint responds immediately with 200 OK to confirm receipt, then processes the contact in the background. A successful response means the submission was accepted — the contact is created or updated moments later.
Tip: You can also pass the API key as a query parameter (
?apiKey=YOUR_API_KEY), but theAuthorization: Bearerheader is preferred and more secure.
The flat contact format
Webhooks use the flat format: a single, top-level JSON object where each field is its own key. You do not wrap the data in a contact object, and you do not use nested arrays for emails, phones, or addresses. Just send simple key/value pairs.
✅ Flat format (use this for webhooks):
{
"firstName": "Jane",
"workEmail": "jane@example.com",
"mobilePhone": "555-0100"
}
❌ Structured format (do not use this for webhooks):
{
"contact": {
"firstName": "Jane",
"emails": [{ "type": "work", "address": "jane@example.com" }]
}
}
The structured format is used by ContactDrive's contacts API for advanced integrations — it isn't what the webhook endpoint expects. Stick with the flat format here.
Minimum required fields
At a minimum, include a first name, a last name, and at least one email address. Submissions without any recognizable contact fields are rejected.
Available flat fields
Name
prefix , firstName , middleName , lastName , suffix , nickname , fullname
Organization
organization , jobTitle
Email (send any or all)
workEmail , homeEmail , otherEmail
Phone (send any or all)
mobilePhone , workPhone , homePhone , otherPhone
Address — use the work , home , or other prefix on each part:
homeStreet , homeStreet2 , homeCity , homeCounty , homeState , homeZip , homeCountry
(and the same with work… and other… prefixes)
Other details
birthdate , gender , rating , website , notes , tags , doNotContact , restrictedContact
Tags — send as a single comma-separated string, e.g. "tags": "vip, newsletter" . These are combined with any tags configured on the webhook itself.
Custom fields
To set a workspace custom field, use its slug as the key. The slug must match a custom field that already exists in your workspace:
{
"firstName": "Jane",
"lastName": "Smith",
"workEmail": "jane@example.com",
"donor_level": "major"
}
You may optionally prefix the slug with customFields. (e.g. "customFields.donor_level" ) — both forms work identically, because the webhook matches the key against your workspace's custom-field slugs either way.
Use the explicit customFields. prefix when a custom-field slug collides with a standard field name (for example, a custom field also slugged notes ). A bare key resolves to the custom field and would shadow the standard one; the prefix makes your intent unambiguous.
Extra / unknown fields are kept
Any field that isn't a recognized contact or custom field — for example tracking parameters like utm_source or campaign_id — isn't discarded. It's stored as metadata on the activity record created for the submission, so the original payload context is preserved.
What happens to the contact
- First name, last name, and email are used to match against existing contacts, so re-submitting the same person updates their record rather than creating a duplicate. This makes form resends safe.
- The contact's source is automatically recorded as a webhook integration.
- An activity is logged using the activity type from the payload (
activityType), or the activity type you set on the webhook, with any extra fields attached as metadata.
Troubleshooting
| Symptom | Likely cause |
|---|---|
Invalid API key |
The API key is missing, wrong, or belongs to a different workspace. |
Webhook not found |
The token in the URL is incorrect — re-copy the endpoint URL from the webhook. |
First name, last name, and email are required |
The payload had no recognizable contact fields — check your field names match the flat format exactly (they're case-sensitive). |
Got 200 OK but no contact appeared |
The request was accepted but failed during processing. Confirm required fields are present and field names are spelled correctly. |