How to Connect Any CRM via HTTP Request Node
Generic guide for Clio, Karbon, ServiceNow, Cosential, etc. REST API basics, auth headers, POST requests.
How to Connect Any CRM via HTTP Request Node
Most professional services CRMs (Clio, Karbon, ServiceNow, Cosential, Unanet) don't have native n8n nodes. You'll connect them using the HTTP Request node and their REST APIs APIsApplication Programming Interface. The connection point that lets two pieces of software exchange data. How n8n talks to your CRM.. This guide shows you exactly how to authenticate, structure requests, and handle responses for any CRM CRMCustomer Relationship Management software. The system of record for contacts, deals, and client communication. Examples: HubSpot, Salesforce, Pipedrive..
What You Need Before Starting
Pull up your CRM's API documentation. You need four pieces of information:
Base URL: The root endpoint for all API calls. Examples:
- Clio:
https://app.clio.com/api/v4 - Karbon:
https://api.karbonhq.com/v3 - ServiceNow:
https://[your-instance].service-now.com/api/now - Cosential:
https://[your-firm].cosential.com/api
Authentication method: Most use one of three approaches:
- API key in header (Clio, Karbon)
- OAuth 2.0 with bearer token (ServiceNow, some Clio instances)
- Basic auth with username/password (older systems)
Rate limits: Note the requests-per-minute cap. Clio allows 500/min, Karbon allows 120/min. You'll need this for error handling.
Endpoint paths: Identify the exact paths for your use case. Creating a contact in Clio uses /contacts.json, while Karbon uses /contacts.
Setting Up Authentication
Authentication goes wrong more than anything else. Here's how to configure each type in n8n.
API Key in Header
Most common for legal and accounting CRMs. Add the HTTP Request node, then:
- Set Authentication to "Generic Credential Type"
- Click "Create New Credential"
- Select "Header Auth"
- Name:
Authorization - Value:
Bearer [your-api-key]orToken [your-api-key](check your CRM's docs for exact format)
For Clio specifically:
- Name:
Authorization - Value:
Bearer YOUR_ACCESS_TOKEN
For Karbon:
- Name:
AccessKey - Value:
YOUR_API_KEY - Add second header:
Acceptwith valueapplication/json
OAuth 2.0
ServiceNow and enterprise CRMs typically use OAuth. You need client ID, client secret, and token URL from your CRM admin panel.
- Set Authentication to "OAuth2"
- Grant Type: "Authorization Code" (most common) or "Client Credentials"
- Authorization URL:
https://[your-instance].service-now.com/oauth_auth.do - Access Token URL:
https://[your-instance].service-now.com/oauth_token.do - Client ID: From your CRM's API settings
- Client Secret: From your CRM's API settings
- Scope: Check docs (ServiceNow uses
useraccount)
Click "Connect my account" and complete the OAuth flow in the popup window.
Basic Auth
Older systems or internal APIs. Least secure, but simplest.
- Set Authentication to "Basic Auth"
- Username: Your API username
- Password: Your API password or token
Creating Records (POST Requests)
Let's create a contact in Clio as a complete example. This pattern works for any CRM.
HTTP Request Node Configuration:
Method: POST
URL: https://app.clio.com/api/v4/contacts.json
Authentication: Header Auth (configured above)
Headers to Add:
Content-Type:application/jsonAccept:application/json
Body (JSON format):
{
"data": {
"first_name": "`{{ $json.firstName }}`",
"last_name": "`{{ $json.lastName }}`",
"type": "Person",
"email_addresses": [
{
"name": "Work",
"address": "`{{ $json.email }}`",
"default_email": true
}
],
"phone_numbers": [
{
"name": "Mobile",
"number": "`{{ $json.phone }}`",
"default_number": true
}
]
}
}
For Karbon (different structure):
{
"PreferredName": "`{{ $json.firstName }}`",
"FamilyName": "`{{ $json.lastName }}`",
"EmailAddresses": [
{
"Email": "`{{ $json.email }}`",
"IsPrimary": true
}
]
}
Notice the differences: Clio wraps everything in a data object and uses snake_case. Karbon uses PascalCase with no wrapper. Always check your CRM's example requests.
Reading Records (GET Requests)
Retrieving data requires query parameters for filtering and pagination.
Fetch all contacts modified in last 24 hours (Clio):
Method: GET
URL: https://app.clio.com/api/v4/contacts.json
Query Parameters:
updated_since:{{ $now.minus({hours: 24}).toISO() }}fields:id,first_name,last_name,email_addresses,updated_atlimit:200
Fetch specific contact by email (Karbon):
Method: GET
URL: https://api.karbonhq.com/v3/Contacts
Query Parameters:
$filter:EmailAddresses/any(e: e/Email eq '{{ $json.email }}')$select:ContactKey,PreferredName,FamilyName
Karbon uses OData query syntax. ServiceNow uses sysparm_query. Read your CRM's filtering documentation carefully.
Updating Records (PUT/PATCH Requests)
Most CRMs use PUT for full updates, PATCH for partial updates.
Update contact phone number (Clio):
Method: PUT
URL: https://app.clio.com/api/v4/contacts/{{ $json.contactId }}.json
Body:
{
"data": {
"phone_numbers": [
{
"id": "`{{ $json.phoneNumberId }}`",
"number": "`{{ $json.newPhone }}`"
}
]
}
}
You need the contact ID and the phone number ID. Always fetch the record first to get nested object IDs.
Handling Pagination
CRMs return 50-200 records per request. Loop through pages to get everything.
Clio pagination pattern:
- Add Loop node after HTTP Request
- Set mode to "Run Once for Each Item"
- In HTTP Request, add query parameter:
cursor:{{ $json.meta.paging.next }}
- Loop continues until
meta.paging.nextis null
Karbon pagination pattern:
- Query parameter:
$skip:{{ $runIndex * 100 }} - Query parameter:
$top:100 - Loop until response returns fewer than 100 records
Error Handling You Actually Need
Add an IF node immediately after your HTTP Request node.
Condition 1 (Success):
{{ $json.statusCode }}equals200or201- Route to your success path
Condition 2 (Rate Limit):
{{ $json.statusCode }}equals429- Add Wait node: 60 seconds
- Add Loop node to retry the request
Condition 3 (Auth Failure):
{{ $json.statusCode }}equals401or403- Send alert via Slack/email
- Stop workflow
Condition 4 (Not Found):
{{ $json.statusCode }}equals404- Handle gracefully (maybe create the record instead of updating)
Everything Else:
- Log the full response:
{{ JSON.stringify($json) }} - Send to error tracking system
Real-World Example: Sync Form Submission to CRM
Complete workflow for capturing a website form and creating a CRM contact.
Trigger: Webhook (receives form POST)
Node 1: HTTP Request (Check if contact exists)
- Method: GET
- URL:
https://app.clio.com/api/v4/contacts.json?query={{ $json.email }}
Node 2: IF (Contact exists?)
- Condition:
{{ $json.data.length > 0 }}
Node 3a: HTTP Request (Update existing - true branch)
- Method: PUT
- URL:
https://app.clio.com/api/v4/contacts/{{ $json.data[0].id }}.json - Body: Updated fields only
Node 3b: HTTP Request (Create new - false branch)
- Method: POST
- URL:
https://app.clio.com/api/v4/contacts.json - Body: Full contact object
Node 4: Set (Extract contact ID)
contactId:{{ $json.data.id }}contactUrl:https://app.clio.com/contacts/{{ $json.data.id }}
Node 5: Slack (Notify team)
- Message:
"New contact created: {{ $json.data.first_name }} {{ $json.data.last_name }}"
This pattern works for any CRM. Swap the URLs and body structure for your system.
Testing Your Integration
Before running in production:
- Test with a sandbox/test account (Clio and ServiceNow provide these)
- Use n8n's "Execute Node" to test individual requests
- Check the "Binary Data" tab in n8n to see raw responses
- Verify rate limits by running 10 requests in quick succession
- Test error scenarios by using invalid IDs or malformed JSON
Create a test contact with email test+[timestamp]@yourfirm.com so you can identify and delete test data easily.
Common Mistakes to Avoid
Hardcoding IDs: Always use expressions like {{ $json.id }} instead of copying IDs from your CRM. IDs change between environments.
Ignoring nested objects: Phone numbers, addresses, and custom fields are usually arrays of objects. You can't just pass a string.
Skipping field validation: CRMs reject requests with invalid data types. If a field expects a number, send {{ parseInt($json.value) }}, not {{ $json.value }}.
Not handling duplicates: Most CRMs don't prevent duplicate records. Always search before creating.
Forgetting timezones: Use ISO 8601 format for dates: {{ $now.toISO() }}. Don't send MM/DD/YYYY strings.
You now have everything needed to connect any REST API-based CRM to n8n. Start with read-only GET requests to verify authentication, then move to creating and updating records once you're confident in your setup.
Related Resources
How to Connect Gmail to n8n (OAuth)
Screenshot-by-screenshot OAuth setup for Gmail trigger and send nodes.
How to Connect Google Calendar to n8n
Calendar trigger node setup with OAuth.
How to Connect HubSpot to n8n
HubSpot API key / OAuth setup, native node configuration.
The full system, end to end.
Looking to build your AI workforce? Get the comprehensive guide for professional services - the 12 plays, the frameworks, and the field-tested playbooks.
Buy on Amazon
Reviewed by Revenue Institute
This guide is actively maintained and reviewed by the implementation experts at Revenue Institute. As the creators of The AI Workforce Playbook, we test and deploy these exact frameworks for professional services firms scaling without new headcount.
Get the Book
Need help turning this guide into reality?
Revenue Institute builds and implements the AI workforce for professional services firms.
Work with Revenue Institute