Quick Intake API
Create intake sessions programmatically from your CRM, automation platform, or custom application. Perfect for GoHighLevel, Zapier, Make.com, and custom integrations.
Base URL
https://intake.link/api/t/{slug}/quick-intakeAPI Key Auth
Secure authentication via header
Instant Sessions
Create intake links in milliseconds
Deduplication
Smart email-based duplicate prevention
Authentication
All API requests require an API key passed in the X-API-Key header.
Getting Your API Key
- Log into your intake.link dashboard
- Go to Settings → Integrations
- Click Generate API Key
- Copy and securely store your key (it won't be shown again)
Security Best Practices
- Never expose your API key in client-side code
- Don't commit API keys to version control
- Use environment variables in production
- Rotate keys periodically
Create Intake Session
/api/t/{slug}/quick-intakeCreates a new intake session and returns a unique URL for the client to complete their intake form. If an active session already exists for the provided email, the existing session is returned instead.
Request Headers
| Header | Value | Required |
|---|---|---|
| Content-Type | application/json | Yes |
| X-API-Key | Your API key | Yes |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | Required | Client's full name |
| string | Optional | Client's email (used for deduplication) | |
| phone | string | Optional | Client's phone number |
| externalId | string | Optional | Your CRM's contact ID (for linking back) |
| id | string | Optional | Alias for externalId (GHL compatibility) |
| source | string | Optional | Lead source identifier (e.g., "GHL", "Zapier") |
| assignedToEmail | string | Optional | Email of staff member to assign. Falls back to default assignee or org owner. |
| intakeTemplateId | string | Optional | Specific intake template ID (from dashboard). Falls back to default template if not provided. |
| notifyEmail | string | Optional | Email to notify when e-sign completes (in addition to tenant notifications). |
| metadata | object | Optional | Arbitrary key-value data from your CRM. Stored with the session and included in webhook payloads. |
| forceNew | boolean | Optional | Bypass email deduplication and always create a new session. Default: false. |
Success Response (New Session)
{
"success": true,
"url": "https://yourfirm.intake.link/i/Xk9mQ2bR",
"staffUrl": "https://yourfirm.intake.link/dashboard/sessions/550e8400-...",
"shortId": "Xk9mQ2bR",
"sessionId": "550e8400-e29b-41d4-a716-446655440000",
"isNew": true,
"intakeTemplateId": "abc123-def456",
"intakeTemplateName": "PI Standard Retainer",
"hasEsign": true,
"hasForm": true,
"hasPayment": false,
"externalId": "ghl_contact_123",
"source": "GHL",
"metadata": { "campaign": "google-ads", "ref": "landing-page-v2" },
"assignedTo": "user_abc123",
"assignedToEmail": "attorney@yourfirm.com",
"assignmentResolution": "provided",
"notifyEmail": "paralegal@firm.com",
"message": "New intake session created using \"PI Standard Retainer\""
}Response Fields
| Field | Description |
|---|---|
| url | Client-facing intake URL to send to the lead |
| staffUrl | Dashboard URL for your staff to manage/view the session |
| shortId | 8-character unique identifier for the session |
| sessionId | Full UUID of the session (for webhook correlation) |
| isNew | Whether a new session was created (false = existing session returned) |
| status | Current session status (only for existing sessions) |
| assignedToEmail | Email of the staff member assigned to this session |
| assignmentResolution | How assignment was resolved: "provided", "default", or "owner" |
| metadata | The metadata object you provided (echoed back) |
Success Response (Existing Session)
If an active session exists for the provided email and template, the API returns it instead of creating a duplicate. Use forceNew: true to bypass this:
{
"success": true,
"url": "https://yourfirm.intake.link/i/Xk9mQ2bR",
"staffUrl": "https://yourfirm.intake.link/dashboard/sessions/550e8400-...",
"shortId": "Xk9mQ2bR",
"sessionId": "550e8400-e29b-41d4-a716-446655440000",
"isNew": false,
"status": "signing",
"intakeTemplateId": "abc123-def456",
"intakeTemplateName": "PI Standard Retainer",
"hasEsign": true,
"hasForm": true,
"externalId": "ghl_contact_123",
"source": "GHL",
"metadata": null,
"notifyEmail": null,
"message": "Existing session found for this email and template"
}Code Examples
cURL
curl -X POST https://intake.link/api/t/yourfirm/quick-intake \
-H "Content-Type: application/json" \
-H "X-API-Key: il_live_your_key_here" \
-d '{
"name": "John Doe",
"email": "john@example.com",
"phone": "555-123-4567",
"externalId": "contact_123",
"source": "GHL",
"assignedToEmail": "attorney@yourfirm.com",
"intakeTemplateId": "abc123-def456",
"notifyEmail": "paralegal@firm.com",
"metadata": { "campaign": "google-ads" }
}'JavaScript / Node.js
const response = await fetch(
'https://intake.link/api/t/yourfirm/quick-intake',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': process.env.INTAKE_LINK_API_KEY,
},
body: JSON.stringify({
name: 'John Doe',
email: 'john@example.com',
phone: '555-123-4567',
externalId: 'contact_123',
source: 'MyApp',
assignedToEmail: 'attorney@yourfirm.com',
intakeTemplateId: 'abc123-def456',
notifyEmail: 'paralegal@firm.com',
metadata: { campaign: 'website', ref: 'contact-form' },
}),
}
);
const data = await response.json();
if (data.success) {
console.log('Client URL:', data.url);
console.log('Staff URL:', data.staffUrl);
console.log('Template:', data.intakeTemplateName);
console.log('Assigned to:', data.assignedToEmail);
} else {
console.error('Error:', data.error);
}GoHighLevel Workflow
Create a workflow with an HTTP Request action:
https://intake.link/api/t/yourfirm/quick-intakeContent-Type: application/jsonX-API-Key: your_api_key
Body (Raw JSON):
{
"id": "{{contact.id}}",
"name": "{{contact.first_name}} {{contact.last_name}}",
"email": "{{contact.email}}",
"phone": "{{contact.phone}}",
"source": "GHL"
}The id field maps to externalId for linking back to your GHL contact.
Zapier Webhook
Configure a Webhooks by Zapier action:
https://intake.link/api/t/yourfirm/quick-intakeContent-Type: application/jsonX-API-Key: your_api_key
Errors & Rate Limits
Error Codes
| Status | Error | Cause |
|---|---|---|
400 | Name is required | Missing or empty name field |
400 | Invalid JSON body | Malformed JSON in request |
400 | Invalid intake template ID | Specified intakeTemplateId doesn't exist |
400 | Intake template is disabled | Specified template exists but is disabled |
401 | API key required | Missing X-API-Key header |
403 | Invalid API key | API key doesn't exist or is revoked |
403 | API key does not match tenant | Key belongs to different tenant |
403 | Tenant is disabled | Account has been disabled |
429 | Rate limit exceeded | Too many requests (see below) |
500 | Failed to create session | Internal server error |
Rate Limits
60 requests per minute
Rate limits are applied per API key. The limit resets after 60 seconds. Responses include a X-RateLimit-Remaining header showing remaining requests.
Webhooks & Events
intake.link can notify your systems when events occur, such as when a client completes their intake form or signs documents.
Available Events
intake.completed— Client finished intake (staff approved)intake.walk_in.received— Walk-in client submitted intakeesignature.completed— Document was signed
Webhooks are configured in your dashboard under Settings → Integrations. We recommend using Make.com for advanced automation workflows.
Inbound Leads API
Receive leads directly into your pipeline from external systems like Make.com, Zapier, or custom integrations. Leads appear in your dashboard and can be converted to intake sessions.
/api/leads/inboundRequest Headers
| Header | Value |
|---|---|
| Authorization | Bearer il_live_xxxxx |
| Content-Type | application/json |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | Required | Lead's full name |
| string | Optional | Lead's email address | |
| phone | string | Optional | Lead's phone number |
| practiceArea | string | Optional | Type of case (e.g., "Personal Injury") |
| notes | string | Optional | Additional notes about the lead |
| sourceId | string | Optional | External ID for deduplication (updates existing lead if matched) |
| assignedToEmail | string | Optional | Staff email to assign this lead to. Falls back to default assignee or org owner. |
| metadata | object | Optional | Custom key-value data to store with the lead |
| source | string | Optional | Lead source identifier (defaults to "webhook") |
Deduplication
If an existing intake session is found for the provided email, the API returns the session info instead of creating a duplicate lead:
{
"success": true,
"existingSession": {
"sessionId": "550e8400-e29b-41d4-a716-446655440000",
"shortId": "Xk9mQ2bR",
"status": "signing",
"assignedTo": "user_abc123",
"assignedToEmail": "staff@yourfirm.com",
"createdAt": "2024-01-15T10:30:00Z"
},
"created": false,
"message": "Existing intake session found for this email"
}Success Response (New Lead)
{
"success": true,
"lead": {
"id": "lead_abc123xyz",
"name": "John Smith",
"email": "john@example.com",
"phone": "(555) 123-4567",
"status": "new",
"source": "webhook",
"sourceId": "rec123abc",
"practiceArea": "Personal Injury",
"assignedTo": "user_xyz789",
"assignedToEmail": "staff@yourfirm.com",
"createdAt": "2024-01-15T10:30:00Z",
"updatedAt": "2024-01-15T10:30:00Z"
},
"created": true
}Staff Assignment
When assignedToEmail is provided, the system looks up the staff member by email. If not found or not provided, it falls back to your configured default assignee, then to the organization owner. This ensures every lead has an owner for visibility and routing in Make.com.
Need Help?
Questions about the API or need help with your integration?
inbox@intake.link