This page documents the customer-facing Dureach API surface that is safe to build against: OAuth service-account management, webhook management and delivery history, and the separately versioned contact-acquisition endpoints. It explains authentication, request fields, response shapes, cursor pagination, filters, limits, and the errors you should handle in production.
Start with the supported boundary
Create an OAuth service account in Settings -> Integrations with the least privilege available to your integration. Keep it server-side, send it in the Authorization header, and scope every request to the intended workspace. The browser application, private runner, and undocumented /api/v1/ or /api/v2/ routes are not automatically customer API endpoints.
The examples below use https://app.dureach.com. Replace YOUR_OAUTH_ACCESS_TOKEN and UUID values with your own values. Never put a live key in a browser bundle, URL, screenshot, log, or support ticket.
Guides
- API authentication and quickstart
- Dureach API access limits
- Connect an AI client via MCP
- MCP tool reference
- MCP approvals, policies, and quotas
- MCP SQL reader
- MCP troubleshooting
- API webhooks
- Webhook setup and delivery monitoring
Authentication
Send the key as a bearer token on every request:
curl --fail-with-body \
'https://app.dureach.com/api/v2/webhooks?limit=25' \
-H 'Authorization: Bearer YOUR_OAUTH_ACCESS_TOKEN' \
-H 'Accept: application/json'Keys belong to the active workspace that created them. A key cannot cross a workspace boundary. If a request returns 401, revoke the key if it may have leaked, create a replacement, and update the server-side secret.
OAuth service-account endpoints
All OAuth service-account endpoints are under /oauth/service-accounts and require the corresponding OAuth business scopes scope (or the matching all:* scope).
POST /oauth/service-accounts
Create a key. The request requires a non-empty name (maximum 255 characters) and a non-empty scopes array. Scope names must be valid and cannot be repeated. The complete key value is returned only in this response.
{
"name": "Reporting integration",
"scopes": ["campaigns:read", "campaigns:create"]
}{
"id": "0199f372-efec-7c2d-af53-85ab8eab7c73",
"name": "Reporting integration",
"scopes": ["campaigns:read", "campaigns:create"],
"key": "dureach_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"workspace_id": "0199f372-efef-73e5-b1ed-e2d1fbe4654d",
"timestamp_created": "2025-10-17T18:33:40.079Z",
"timestamp_updated": "2025-10-17T18:33:40.079Z"
}GET /oauth/service-accounts
List keys in the active workspace. Query parameters:
| Parameter | Required | Details |
|---|---|---|
limit | No | Number of records, default 25. Use a positive integer; the server bounds the page size. |
starting_after | No | UUID of the last key from the previous page. Pass next_starting_after unchanged. |
The response contains items and, when another page exists, next_starting_after. A later read returns only a safe key prefix, never the original secret.
DELETE /oauth/service-accounts/{id}
Revoke a key. The response contains the deleted key metadata and a safe prefix. Treat a successful deletion as permanent and remove the key from your secret manager.
Webhook endpoints
Webhook endpoints are under /api/v2 and require webhooks:* (or the matching all:*) plus a plan that includes webhooks.
GET /api/v2/webhooks
List webhook destinations. Supported filters are campaign (campaign UUID) and event_type. Use limit and starting_after for cursor pagination. The server accepts a page size from 1 through 100; the default is 25. The response is:
{
"items": [
{
"id": "0199f372-efec-7c2d-af53-85ab8eab7c73",
"campaign": "0199f372-efef-73e5-b1ed-e2d1fbe4654d",
"name": "Interested lead receiver",
"target_hook_url": "https://example.com/dureach-hook",
"event_type": "lead.interested",
"custom_interest_value": null,
"timestamp_created": "2025-10-17T18:33:40.079Z"
}
],
"next_starting_after": "0199f372-efec-7c2d-af53-85ab8eab7c73"
}POST /api/v2/webhooks
Create a destination. Send target_hook_url, name, event_type, and, when the event is a custom interest label, custom_interest_value. campaign is optional when the webhook should receive workspace-level events.
GET /api/v2/webhooks/{id}, PATCH /api/v2/webhooks/{id}, DELETE /api/v2/webhooks/{id}
Read, update, or delete one destination. PATCH accepts the same fields as create and only changes the fields provided. Confirm the destination after an update; deleting it does not delete historical delivery events.
GET /api/v2/webhooks/event-types
Return standard event types plus custom lead-label events available in the active workspace. Use the returned id as event_type; do not hard-code a custom label that may later be renamed.
POST /api/v2/webhooks/{id}/test
Send a test delivery. A successful response has success: true, status_code: 200, response_time_ms, and error: null. Test against a non-production receiver first.
GET /api/v2/webhook-events
List delivery attempts. Filter with success=true|false or webhook_url. Use limit (1-100, default 25) and starting_after. Events include payload, status_code, success, retry_count, will_retry, timestamp_next_retry, error_message, retry_successful, lead_email, and response_time_ms. Redact payload and lead_email before writing application logs.
GET /api/v2/webhook-events/{id}
Read one delivery attempt by UUID.
GET /api/v2/webhook-events/summary and GET /api/v2/webhook-events/summary-by-date
Return aggregate delivery health. The summary includes total_events, successful_events, failed_events, success_rate, and failure_rate. The date summary returns an items array with one record per date. Use these endpoints for monitoring, not for replaying events.
Contact acquisition endpoints
The contact-acquisition service currently exposes these legacy, separately metered endpoints under /api/v1/leadbank. Availability depends on workspace entitlement:
| Method | Path | Purpose |
|---|---|---|
POST | /api/v1/leadbank/find | Search for contacts using the supported search payload. |
POST | /api/v1/leadbank/acquire_email | Request a work-email reveal for an eligible contact. |
GET | /api/v1/leadbank/balance/get | Read the current acquisition balance. |
GET | /api/v1/leadbank/acquire-lists | List acquisition lists. |
GET | /api/v1/leadbank/acquire-lists/{list_id}/leads | List leads in one acquisition list. |
GET | /leadbank/api/v1/company/{company_id} | Read the company record for an acquired company. |
Search and list responses can be large, so always send the documented page or limit parameters returned by the endpoint and stop when the response reports no next page. An empty result means no match for that query; it is not proof that a person or company does not exist.
Request hygiene
Use the documented method and path, validate request fields before sending, follow the endpoint’s cursor or bounded page parameters, and handle 401, 403, validation, rate, and server errors separately. Make webhook consumers idempotent: store the event identifier before acknowledging it and retry safely after transient failures.
Errors
OAuth service-account management returns JSON with statusCode, error, and message; newer endpoints may also include a machine-readable code. Treat 400 as invalid input, 401 as missing, invalid, or revoked authentication, 403 as a scope, role, workspace, or plan failure, 404 as an unknown resource, 409 as a state conflict, and 429 as a rate or usage limit. Retry only bounded, idempotent requests after transient 5xx failures; do not retry a 4xx response blindly.
Troubleshooting checklist
- Confirm the base URL is
https://app.dureach.comand the path includes the correct version. - Send
Authorization: Bearer YOUR_OAUTH_ACCESS_TOKEN; do not use a query-string key. - Check the key scopes and active workspace, then confirm the plan includes the endpoint.
- Validate UUIDs, required fields,
limitrange, andstarting_aftercursor. - Record the response status, redacted
messageorcode, request time, and endpoint for support. - Revoke and replace a key if it was exposed. Never send the key or an unredacted webhook payload to support.
Endpoint workflow
- Create an OAuth service account in Settings → Integrations and select the smallest scopes needed.
- Send a read-only request with
Authorization: Bearer YOUR_OAUTH_ACCESS_TOKENandAccept: application/json. - Validate the response shape before writing an integration: preserve
items, UUIDs, enum values, andnext_starting_after. - Use cursor pagination exactly as returned and stop when the cursor is absent.
- Make webhook consumers idempotent by storing the event ID before acknowledging the delivery.
Request field rules
Use positive bounded limit values, valid UUIDs, documented event types, and complete required JSON fields. Do not put keys in query strings, browser bundles, screenshots, or logs.
Campaign and lead API
These are the supported campaign and lead operations for a scoped workspace OAuth service account. Create the key in Settings -> Integrations, save it when it is shown once, and keep it on your server. The workspace plan must include API access. Use https://api.dureach.com for the requests below.
| Method | Path | Required key scope | Purpose |
|---|---|---|---|
GET | /api/v2/campaigns | campaigns:read | List campaigns |
POST | /api/v2/campaigns | campaigns:create | Create a campaign |
GET | /api/v2/campaigns/{id} | campaigns:read | Read a campaign |
PATCH | /api/v2/campaigns/{id} | campaigns:update | Update a campaign |
POST | /api/v2/lead/add | leads:create | Add leads to a campaign |
GET | /api/v2/lead/get | leads:read | Find a lead by email |
POST | /api/v2/lead/update/status | leads:update | Update lead status |
Start with a read-only request:
curl --fail-with-body 'https://api.dureach.com/api/v2/campaigns?limit=10' \
-H 'Authorization: Bearer YOUR_OAUTH_ACCESS_TOKEN' \
-H 'Accept: application/json'The campaign list returns items and may return next_starting_after. Pass that cursor unchanged on the next request. limit is bounded to 100. Use a UUID from the response for the detail and update paths.
To add a lead, send a JSON body to POST /api/v2/lead/add:
{
"campaign_id": "CAMPAIGN_UUID",
"leads": [{"email": "[email protected]", "first_name": "Jane"}]
}Look up that lead with GET /api/v2/lead/get?email=jane%40example.com&campaign_id=CAMPAIGN_UUID. To change its status, send campaign_id, email, and new_status to POST /api/v2/lead/update/status. Campaign creation and updates use JSON; see the OpenAPI schemas for required schedule and sequence fields.
The key is bound to its workspace. A mismatched X-Workspace-ID is rejected. Missing or invalid keys return 401; missing scopes and workspace mismatches return 403. Handle validation errors and rate limits separately. Do not put the key in a URL, browser bundle, screenshot, or log.
The machine-readable OpenAPI contract defines request fields, responses, and the bearer scheme for these seven operations.