Summary and recommendation
Drift exposes a REST API at https://driftapi.com supporting OAuth 2.0 (authorization code flow) and Personal Access Token (Bearer) authentication. A critical architectural distinction: the REST API manages contacts (end-user/visitor records), not Drift seat holders.
Agent provisioning and deprovisioning is handled exclusively through the SCIM 2.0 endpoint at https://driftapi.com/scim/v2, which requires an Enterprise plan and a fully operational SSO configuration as a prerequisite.
Building an identity graph that spans both visitor contacts and internal agents therefore requires combining REST API calls (for contact data) with SCIM operations (for agent lifecycle), as neither surface covers both object types alone.
API quick reference
| Has user API | Yes |
| Auth method | OAuth 2.0 (app-based) or Personal Access Token (Bearer token) |
| Base URL | Official docs |
| SCIM available | Yes |
| SCIM plan required | Enterprise |
Authentication
Auth method: OAuth 2.0 (app-based) or Personal Access Token (Bearer token)
Setup steps
- Navigate to Drift Developer Portal (https://dev.drift.com) and create an app.
- For OAuth 2.0: configure redirect URIs, obtain client_id and client_secret, implement authorization code flow to receive access_token.
- For Personal Access Token: go to Drift Settings > Integrations > API, generate a token.
- Include token in all requests as HTTP header: Authorization: Bearer
.
Required scopes
| Scope | Description | Required for |
|---|---|---|
| contact_read | Read contact/user records | GET contact endpoints |
| contact_write | Create and update contact/user records | POST/PATCH contact endpoints |
| user_read | Read Drift team member (agent) records | GET /users endpoints |
User object / data model
| Field | Type | Description | On create | On update | Notes |
|---|---|---|---|---|---|
| id | integer | Unique Drift contact identifier | system-assigned | immutable | Used as path param for contact operations |
| string | Primary email address of the contact | required | optional | Used as lookup key; must be unique | |
| name | string | Full name of the contact | optional | optional | |
| phone | string | Phone number | optional | optional | |
| company | string | Company name associated with the contact | optional | optional | |
| title | string | Job title | optional | optional | |
| createdAt | timestamp (ms) | Unix timestamp (milliseconds) when contact was created | system-assigned | immutable | |
| updatedAt | timestamp (ms) | Unix timestamp (milliseconds) of last update | system-assigned | system-assigned | |
| attributes | object | Key-value map of custom and standard contact attributes | optional | optional | Custom attributes must be pre-defined in Drift settings |
| socialProfiles | object | Social profile URLs (twitter, linkedin, etc.) | optional | optional | |
| externalId | string | External system identifier for the contact | optional | optional | Useful for CRM sync |
| ownerId | integer | Drift user (agent) ID assigned as contact owner | optional | optional |
Core endpoints
List contacts
- Method: GET
- URL:
https://driftapi.com/contacts - Watch out for: Pagination uses a cursor token in the 'next' field; pass as query param on subsequent requests.
Request example
GET /contacts?limit=25 HTTP/1.1
Authorization: Bearer <token>
Response example
{
"data": [{"id":123,"email":"user@example.com"}],
"next": "cursor_token"
}
Get contact by ID
- Method: GET
- URL:
https://driftapi.com/contacts/{contactId} - Watch out for: Returns 404 if contact does not exist; no upsert behavior on GET.
Request example
GET /contacts/123 HTTP/1.1
Authorization: Bearer <token>
Response example
{
"data": {
"id": 123,
"email": "user@example.com",
"attributes": {"name":"Jane Doe"}
}
}
Create contact
- Method: POST
- URL:
https://driftapi.com/contacts - Watch out for: Duplicate email will update the existing contact rather than creating a new one.
Request example
POST /contacts HTTP/1.1
Authorization: Bearer <token>
Content-Type: application/json
{"email":"new@example.com","attributes":{"name":"John"}}
Response example
{
"data": {
"id": 456,
"email": "new@example.com"
}
}
Update contact
- Method: PATCH
- URL:
https://driftapi.com/contacts/{contactId} - Watch out for: Only fields included in the payload are updated; omitted fields are unchanged.
Request example
PATCH /contacts/123 HTTP/1.1
Authorization: Bearer <token>
Content-Type: application/json
{"attributes":{"title":"VP Sales"}}
Response example
{
"data": {
"id": 123,
"attributes": {"title":"VP Sales"}
}
}
Delete contact
- Method: DELETE
- URL:
https://driftapi.com/contacts/{contactId} - Watch out for: Deletion is permanent; no soft-delete or recovery endpoint documented.
Request example
DELETE /contacts/123 HTTP/1.1
Authorization: Bearer <token>
Response example
HTTP 200 OK
{"data":{"id":123}}
List team users (agents)
- Method: GET
- URL:
https://driftapi.com/users - Watch out for: Returns Drift seat holders (agents), not end-user contacts. Requires user_read scope.
Request example
GET /users HTTP/1.1
Authorization: Bearer <token>
Response example
{
"data": [{"id":1,"name":"Agent A","email":"agent@co.com"}]
}
Get team user by ID
- Method: GET
- URL:
https://driftapi.com/users/{userId} - Watch out for: Agent management (invite/deactivate) is not available via REST API; use SCIM for provisioning.
Request example
GET /users/1 HTTP/1.1
Authorization: Bearer <token>
Response example
{
"data": {"id":1,"name":"Agent A","email":"agent@co.com","role":"admin"}
}
Get contact by email
- Method: GET
- URL:
https://driftapi.com/contacts/by_email?email={email} - Watch out for: Email must be URL-encoded. Returns 404 if not found.
Request example
GET /contacts/by_email?email=user@example.com HTTP/1.1
Authorization: Bearer <token>
Response example
{
"data": {"id":123,"email":"user@example.com"}
}
Rate limits, pagination, and events
- Rate limits: Drift enforces per-token rate limits. Official documentation states limits vary by plan; commonly cited as 200 requests per minute for standard API access.
- Rate-limit headers: Yes
- Retry-After header: No
- Rate-limit notes: HTTP 429 returned when limit exceeded. Check response headers for rate limit state. Exact header names not publicly documented.
- Pagination method: cursor
- Default page size: 25
- Max page size: 100
- Pagination pointer: next
| Plan | Limit | Concurrent |
|---|---|---|
| Premium | 200 requests/minute | 0 |
| Advanced/Enterprise | Higher limits available; contact Drift/Salesloft | 0 |
- Webhooks available: Yes
- Webhook notes: Drift supports webhooks for real-time event notifications. Webhooks are configured in the Drift developer app settings and deliver HTTP POST payloads to a specified endpoint.
- Alternative event strategy: Poll GET /contacts or GET /conversations endpoints for environments where webhooks are not feasible.
- Webhook events: contact_identified, new_message, new_conversation, conversation_status_updated, meeting_booked, button_action
SCIM API status
SCIM available: Yes
SCIM version: 2.0
Plan required: Enterprise
Endpoint: https://driftapi.com/scim/v2
Supported operations: GET /Users, GET /Users/{id}, POST /Users, PUT /Users/{id}, PATCH /Users/{id}, DELETE /Users/{id}
Limitations:
- Requires Enterprise plan
- SSO must be configured as a prerequisite before enabling SCIM
- Group provisioning support not confirmed in public documentation
- Supported IdPs confirmed: Okta, OneLogin; Entra ID (Azure AD) not confirmed
Common scenarios
Three integration patterns are well-supported by the available endpoints. First, CRM-to-Drift contact sync: use GET /contacts/by_email?
email={email} to check existence, then branch to PATCH /contacts/{id} on a 200 or POST /contacts on a 404 - note that POST with a duplicate email performs a silent upsert, so always capture the returned id to confirm which record was written.
Second, agent provisioning via SCIM: configure your IdP (Okta or OneLogin are confirmed.
Entra ID support is not documented) against https://driftapi.com/scim/v2, then manage agent lifecycle entirely through IdP assignment and unassignment - SCIM deprovisioning removes seat access but does not purge contact data associated with that agent.
Third, event-driven enrichment via webhooks: register for new_conversation events, extract the contactId from the payload, and call GET /contacts/{contactId} to enrich before routing - webhook delivery is not guaranteed to be ordered or deduplicated, so implement idempotency keyed on the event or conversation id.
Sync CRM contacts into Drift
- Authenticate using a Personal Access Token or OAuth 2.0 access token.
- For each CRM contact, call GET /contacts/by_email?email={email} to check existence.
- If contact exists (200), call PATCH /contacts/{id} with updated attributes.
- If contact does not exist (404), call POST /contacts with email and attributes payload.
- Store returned Drift contact id mapped to CRM record for future updates.
Watch out for: POST /contacts with a duplicate email performs an upsert silently; always check the returned id to confirm which record was affected.
Provision and deprovision Drift agents via SCIM (Enterprise)
- Confirm Enterprise plan and SSO (Okta or OneLogin) is configured in Drift settings.
- In your IdP, add Drift as a SCIM application using base URL https://driftapi.com/scim/v2 and a SCIM Bearer token from Drift settings.
- Assign users in the IdP to the Drift SCIM app to trigger POST /Users provisioning.
- Unassign or deactivate users in the IdP to trigger DELETE /Users/{id} or PATCH /Users/{id} (active=false) deprovisioning.
Watch out for: SSO must be fully operational before SCIM activation. Deprovisioning via SCIM removes Drift seat access but contact data associated with that agent may remain.
React to new conversations via webhook
- Register a webhook endpoint URL in the Drift developer app settings for the new_conversation event.
- Drift will POST a JSON payload to your endpoint when a new conversation starts.
- Parse the payload to extract contactId, then call GET /contacts/{contactId} to enrich with contact attributes.
- Use enriched data to route, tag, or update the conversation via subsequent API calls.
Watch out for: Webhook delivery is not guaranteed to be ordered or deduplicated; implement idempotency using the conversation or event id in the payload.
Why building this yourself is a trap
OAuth 2.0 access tokens do not auto-refresh; applications that do not implement the refresh_token grant will silently lose API access after token expiry.
Rate limits are enforced at 200 requests per minute on Premium, with HTTP 429 returned on breach - response headers carry rate limit state, but the header names are not publicly documented, making defensive retry logic harder to implement precisely.
Custom contact attributes must be created in the Drift settings UI before they can be written via API; attempting to write to an undeclared attribute will not produce a useful error.
Finally, Drift's ongoing integration into Salesloft means some documentation URLs are deprecated or redirecting - treat devdocs.drift.com as the authoritative source and verify any endpoint behavior against live responses rather than cached documentation.
Automate Drift workflows without one-off scripts
Stitchflow builds and maintains end-to-end IT automation across your SaaS stack, including apps without APIs. Built for exactly how your company works, with human approvals where they matter.