n8n
Add a contact from a form, and start a workflow when a contact is created. Both use n8n’s HTTP Request node with header authentication.
Set up the key
- In ContactZapp, create an API key with both scopes. See Getting started.
- In n8n, open Credentials, then Create credential, and choose Header Auth. Fill it in as below, and name it
ContactZapp API key.Field Value Name AuthorizationValue Bearer cz_live_… (your key)
Add a contact from a form
The workflow takes the fields of a form submission and sends them to POST /api/v1/contacts. The first node stands in for your form: replace it with n8n’s Form Trigger, a Webhook, or whatever starts your workflow.
The HTTP Request node is set like this:
| Setting | Value |
|---|---|
| Method | POST |
| URL | https://app.contactz.app/api/v1/contacts |
| Authentication | Generic Credential Type, then Header Auth: ContactZapp API key |
| Send Headers | On. Idempotency-Key is a value that is yours for this one submission, such as the submission id. |
| Send Body | On, JSON, using the fields of a contact. See Creating and changing contacts. |
| Settings, Retry On Fail | On, 3 tries. The Idempotency-Key makes a retry safe. |
The workflow, to paste into n8n
Copy it, then paste it onto the n8n canvas. Choose your own credential on the HTTP Request node.
{
"name": "ContactZapp: add a contact",
"nodes": [
{
"parameters": {},
"name": "Start",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [
0,
0
]
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "a1",
"name": "submissionId",
"value": "form-1001",
"type": "string"
},
{
"id": "a2",
"name": "firstName",
"value": "Grace",
"type": "string"
},
{
"id": "a3",
"name": "lastName",
"value": "Hopper",
"type": "string"
},
{
"id": "a4",
"name": "email",
"value": "[email protected]",
"type": "string"
},
{
"id": "a5",
"name": "phone",
"value": "+1 202 555 0147",
"type": "string"
},
{
"id": "a6",
"name": "company",
"value": "Navy",
"type": "string"
}
]
},
"options": {}
},
"name": "Form data",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
220,
0
]
},
{
"parameters": {
"method": "POST",
"url": "https://app.contactz.app/api/v1/contacts",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Idempotency-Key",
"value": "={{ $json.submissionId }}"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ { firstName: $json.firstName, lastName: $json.lastName, organization: $json.company, emails: [{ label: 'work', value: $json.email }], phones: [{ label: 'mobile', value: $json.phone }] } }}",
"options": {}
},
"name": "Add contact",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
440,
0
],
"retryOnFail": true,
"maxTries": 3,
"waitBetweenTries": 5000,
"credentials": {
"httpHeaderAuth": {
"id": "REPLACE",
"name": "ContactZapp API key"
}
}
}
],
"connections": {
"Start": {
"main": [
[
{
"node": "Form data",
"type": "main",
"index": 0
}
]
]
},
"Form data": {
"main": [
[
{
"node": "Add contact",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
}
}The answer has an outcome: created, merged or needs_review. Add an IF node after the HTTP Request node if your workflow should act on it.
Start a workflow when a contact is created
n8n has no ContactZapp trigger, so the workflow polls GET /api/v1/triggers/contact.created every 5 minutes. Each event has a stable id. The Remove Duplicates node remembers the ids it has seen, so a later run passes on only the new events.
The workflow, to paste into n8n
{
"name": "ContactZapp: a contact was created",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "minutes",
"minutesInterval": 5
}
]
}
},
"name": "Every 5 minutes",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [
0,
0
]
},
{
"parameters": {
"url": "https://app.contactz.app/api/v1/triggers/contact.created",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "limit",
"value": "50"
}
]
},
"options": {}
},
"name": "Get new contacts",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
220,
0
],
"credentials": {
"httpHeaderAuth": {
"id": "REPLACE",
"name": "ContactZapp API key"
}
}
},
{
"parameters": {
"fieldToSplitOut": "items",
"options": {}
},
"name": "One item per event",
"type": "n8n-nodes-base.splitOut",
"typeVersion": 1,
"position": [
440,
0
]
},
{
"parameters": {
"operation": "removeItemsSeenInPreviousExecutions",
"dedupeValue": "={{ $json.id }}",
"options": {}
},
"name": "Only events not seen before",
"type": "n8n-nodes-base.removeDuplicates",
"typeVersion": 2,
"position": [
660,
0
]
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "b1",
"name": "name",
"value": "={{ $json.contact.displayName }}",
"type": "string"
},
{
"id": "b2",
"name": "email",
"value": "={{ $json.contact.emails[0]?.value ?? '' }}",
"type": "string"
},
{
"id": "b3",
"name": "frozen",
"value": "={{ $json.contact.frozen }}",
"type": "boolean"
}
]
},
"options": {}
},
"name": "Your next step",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
880,
0
]
}
],
"connections": {
"Every 5 minutes": {
"main": [
[
{
"node": "Get new contacts",
"type": "main",
"index": 0
}
]
]
},
"Get new contacts": {
"main": [
[
{
"node": "One item per event",
"type": "main",
"index": 0
}
]
]
},
"One item per event": {
"main": [
[
{
"node": "Only events not seen before",
"type": "main",
"index": 0
}
]
]
},
"Only events not seen before": {
"main": [
[
{
"node": "Your next step",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
}
}Tested with n8n 1.100.1.