Reference
API reference
Every operation of the API by resource, generated from the API's own contracts.
Every operation of the API, generated from the same contracts that produce the OpenAPI document (OpenAPI 3.1, 123 operations today). Base URL: https://api.dmhero.ai. Every request needs an API key in Authorization: Bearer except the OpenAPI document itself.
Operations appear here as they ship. The changelog records each addition; additions never change the API version.
Me
| Operation | Method and path | Summary | Scopes |
|---|---|---|---|
| me.get | GET /v1/me | Who this API key is: its workspace, scopes, reps and limits. | any key |
Leads
| Operation | Method and path | Summary | Scopes |
|---|---|---|---|
| leads.list | GET /v1/leads | List the workspace's leads, newest first, with filters. | leads:read |
| leads.upsert | POST /v1/leads | Create or update one lead, or a batch of up to 100. | leads:write |
| leads.get | GET /v1/leads/{lead_id} | One lead. The ETag header is the version PATCH accepts as If-Match. | leads:read |
| leads.update | PATCH /v1/leads/{lead_id} | Change a lead's fields. Send If-Match with the ETag you read to refuse a concurrent change. | leads:write |
| leads.delete | DELETE /v1/leads/{lead_id} | Delete a lead, its tags and its enrollments. | leads:delete |
| leads.tags.add | POST /v1/leads/{lead_id}/tags | Add tags to a lead. Tags it already has are left as they are. | leads:write |
| leads.tags.remove | DELETE /v1/leads/{lead_id}/tags/{tag} | Remove one tag from a lead (URL-encode the tag). Removing a tag the lead does not have is not an error. | leads:write |
| leads.lookup | GET /v1/leads/lookup | Where the lead with this Instagram handle stands: status, setter stage, tags, campaign. | leads:read |
| tags.list | GET /v1/tags | Every tag used on the workspace's leads, alphabetical. | leads:read |
Folders
| Operation | Method and path | Summary | Scopes |
|---|---|---|---|
| folders.list | GET /v1/folders | The workspace's lead folders with their lead counts, and how many leads are in none. | leads:read |
| folders.create | POST /v1/folders | Create a lead folder. | leads:write |
| folders.update | PATCH /v1/folders/{folder_id} | Rename a lead folder. | leads:write |
| folders.delete | DELETE /v1/folders/{folder_id} | Delete a lead folder. Its leads are kept and end up in no folder. | leads:write |
Custom fields
| Operation | Method and path | Summary | Scopes |
|---|---|---|---|
| custom_fields.list | GET /v1/custom-fields | The workspace's custom fields (at most 5) and how many leads carry each. | leads:read |
| custom_fields.create | POST /v1/custom-fields | Define a custom field. The key is derived from the label unless given, and never changes. | leads:write |
| custom_fields.update | PATCH /v1/custom-fields/{key} | Rename a custom field's label. The key stays. | leads:write |
| custom_fields.delete | DELETE /v1/custom-fields/{key} | Delete a custom field and strip its value from every lead of the workspace. Needs confirm=true. | leads:delete |
Suppressions
| Operation | Method and path | Summary | Scopes |
|---|---|---|---|
| suppressions.list | GET /v1/suppressions | Leads marked not_interested: outreach never contacts them. | leads:read |
| suppressions.add | POST /v1/suppressions | Suppress Instagram handles: every lead with the handle becomes not_interested, and an unknown handle becomes a suppressed lead. | leads:write |
| suppressions.remove | DELETE /v1/suppressions/{ig_handle} | Lift a suppression: the handle's not_interested leads go back to new. | leads:write |
Jobs
| Operation | Method and path | Summary | Scopes |
|---|---|---|---|
| jobs.list | GET /v1/jobs | The workspace's jobs, newest first. | leads:read |
| jobs.get | GET /v1/jobs/{job_id} | One job: its status, progress and result counts. | leads:read |
| jobs.cancel | POST /v1/jobs/{job_id}/cancel | Cancel a job. A running job stops at its next slice; work already done stays done. | leads:write |
| jobs.result | GET /v1/jobs/{job_id}/result | The CSV file an export job built (text/csv), for 24 hours after it finished. | leads:read |
| leads.bulk.preview | POST /v1/leads/bulk-actions | Preview a bulk action on up to 30 000 leads; the target is frozen until you confirm. | leads:write |
| leads.bulk.confirm | POST /v1/leads/bulk-actions/{job_id}/confirm | Confirm a previewed bulk action: the job is queued and runs on the frozen target. | leads:write |
| leads.exports.create | POST /v1/leads/exports | Export the leads a filter selects as a CSV file, built by a job. | leads:read |
| leads.imports.create | POST /v1/leads/imports | Import up to 30 000 leads as a job, from JSON or a CSV body. | leads:write |
Templates
| Operation | Method and path | Summary | Scopes |
|---|---|---|---|
| templates.list | GET /v1/templates | List the workspace's message templates, newest first. | templates:read |
| templates.create | POST /v1/templates | Create a message template. | templates:write |
| templates.get | GET /v1/templates/{template_id} | Read one template. | templates:read |
| templates.update | PATCH /v1/templates/{template_id} | Change a template's name, category, content or variant. | templates:write |
| templates.delete | DELETE /v1/templates/{template_id} | Delete a template and its version history. | templates:write |
| templates.stats | GET /v1/templates/{template_id}/stats | Sends and replies of one template. | templates:read |
| templates.versions.list | GET /v1/templates/{template_id}/versions | List a template's earlier contents, newest version first. | templates:read |
| templates.spintax.propose | POST /v1/templates/spintax-proposals | Propose version groups for a template body (AI). | templates:write |
| templates.validate | POST /v1/templates/validate | Check a template body before saving it. | templates:read |
Campaigns
| Operation | Method and path | Summary | Scopes |
|---|---|---|---|
| campaign_leads.upsert_enroll | POST /v1/campaign-leads | Upsert one lead, then enroll it into a campaign (the Clay add-to-campaign column). | leads:write, enrollments:write |
| campaigns.list | GET /v1/campaigns | List the workspace's campaigns, newest first. | campaigns:read |
| campaigns.create | POST /v1/campaigns | Create a campaign, optionally with its steps. It starts paused. | campaigns:write |
| campaigns.get | GET /v1/campaigns/{campaign_id} | Get one campaign with its steps. | campaigns:read |
| campaigns.update | PATCH /v1/campaigns/{campaign_id} | Update a campaign's settings. | campaigns:write |
| campaigns.delete | DELETE /v1/campaigns/{campaign_id} | Delete a campaign with its steps and enrollments. | campaigns:write |
| campaigns.archive | POST /v1/campaigns/{campaign_id}/archive | Archive a campaign: every enrollment stops sending. | campaigns:control |
| campaigns.clone | POST /v1/campaigns/{campaign_id}/clone | Copy a campaign and its steps, without its enrollments. The copy starts paused. | campaigns:write |
| campaigns.pause | POST /v1/campaigns/{campaign_id}/pause | Pause an active campaign. | campaigns:control |
| campaigns.resume | POST /v1/campaigns/{campaign_id}/resume | Resume a paused campaign. | campaigns:control |
| campaigns.start | POST /v1/campaigns/{campaign_id}/start | Start a paused campaign. | campaigns:control |
| campaigns.stats | GET /v1/campaigns/{campaign_id}/stats | A campaign's funnel and enrollment numbers. | campaigns:read |
| campaigns.steps.replace | PUT /v1/campaigns/{campaign_id}/steps | Replace a campaign's whole step sequence. | campaigns:write |
Enrollments
| Operation | Method and path | Summary | Scopes |
|---|---|---|---|
| enrollments.list | GET /v1/campaigns/{campaign_id}/enrollments | List a campaign's enrollments, newest first. | campaigns:read |
| enrollments.create | POST /v1/campaigns/{campaign_id}/enrollments | Enroll leads in a campaign, by id or by filter. | enrollments:write |
| enrollments.remove | DELETE /v1/campaigns/{campaign_id}/enrollments/{lead_id} | Remove a lead from a campaign: nothing more is sent to it from this campaign. | enrollments:write |
| enrollments.get | GET /v1/enrollments/{enrollment_id} | Get one enrollment. | campaigns:read |
| enrollments.pause | POST /v1/enrollments/{enrollment_id}/pause | Pause one enrollment (active -> paused); one already paused is answered as is. | enrollments:write |
| enrollments.resume | POST /v1/enrollments/{enrollment_id}/resume | Resume one enrollment (paused -> active); one already active is answered as is. | enrollments:write |
| leads.enrollments.list | GET /v1/leads/{lead_id}/enrollments | Every campaign enrollment of one lead, newest first. | campaigns:read |
Reps
| Operation | Method and path | Summary | Scopes |
|---|---|---|---|
| reps.list | GET /v1/reps | List the workspace's connected reps with their health and setter mode. | reps:read |
| reps.get | GET /v1/reps/{rep_id} | Read one rep with its health and setter mode. | reps:read |
| reps.excluded.list | GET /v1/reps/{rep_id}/excluded-handles | List the handles a rep's inbound setter never engages and never adds to the CRM. | reps:read |
| reps.excluded.add | POST /v1/reps/{rep_id}/excluded-handles | Add handles to a rep's inbound exclusion list. | reps:write |
| reps.excluded.remove | DELETE /v1/reps/{rep_id}/excluded-handles/{handle} | Remove one handle from a rep's inbound exclusion list. | reps:write |
| reps.setter_mode.get | GET /v1/reps/{rep_id}/setter-mode | Read a rep's AI Setter mode for outbound replies and for inbound DMs. | reps:read |
| reps.setter_mode.set | PUT /v1/reps/{rep_id}/setter-mode | Set a rep's AI Setter mode for outbound replies, inbound DMs, or both. | reps:write |
Analytics
| Operation | Method and path | Summary | Scopes |
|---|---|---|---|
| analytics.ab_comparison | GET /v1/analytics/ab-comparison | Reply performance compared across campaigns, templates or niches, with comparability findings. | analytics:read |
| analytics.funnel | GET /v1/analytics/funnel | The lead status funnel and the daily cohort series of first DMs. | analytics:read |
| analytics.overview | GET /v1/analytics/overview | Headline numbers: leads, reach, replies and conversions, plus the reps' threads and today's sends. | analytics:read |
| analytics.setter | GET /v1/analytics/setter | The AI Setter report for one rep: variants, funnel, turns, follow-ups, silence, segments, objections. | analytics:read |
Conversations
| Operation | Method and path | Summary | Scopes |
|---|---|---|---|
| conversations.list | GET /v1/conversations | List conversations, newest activity first. | conversations:read |
| conversations.get | GET /v1/conversations/{conversation_id} | Read one conversation. | conversations:read |
| conversations.archive | POST /v1/conversations/{conversation_id}/archive | Archive a conversation. | conversations:state |
| conversations.drafts.list | GET /v1/conversations/{conversation_id}/drafts | List the AI Setter's pending draft of a conversation. | setter:read |
| conversations.drafts.approve | POST /v1/conversations/{conversation_id}/drafts/{draft_id}/approve | Approve the AI Setter's draft: send it unchanged. | setter:write |
| conversations.drafts.dismiss | POST /v1/conversations/{conversation_id}/drafts/{draft_id}/dismiss | Dismiss the AI Setter's draft without sending it. | setter:write |
| conversations.mark_read | POST /v1/conversations/{conversation_id}/read | Mark a conversation read. | conversations:state |
| conversations.setter.hand | POST /v1/conversations/{conversation_id}/setter/hand | Hand a conversation to the AI Setter. | setter:write |
| conversations.setter.resume | POST /v1/conversations/{conversation_id}/setter/resume | Resume the AI Setter on a conversation handed to a person. | setter:write |
| conversations.star | POST /v1/conversations/{conversation_id}/star | Star a conversation. | conversations:state |
| conversations.unarchive | POST /v1/conversations/{conversation_id}/unarchive | Move a conversation back to active. | conversations:state |
| conversations.unstar | POST /v1/conversations/{conversation_id}/unstar | Remove the star from a conversation. | conversations:state |
Webhooks
| Operation | Method and path | Summary | Scopes |
|---|---|---|---|
| webhooks.deliveries.redeliver | POST /v1/webhook-deliveries/{delivery_id}/redeliver | Send a finished delivery again: the same delivery id, event id and payload. | webhooks:manage |
| webhooks.endpoints.list | GET /v1/webhook-endpoints | The workspace's webhook endpoints (at most 15). | webhooks:manage |
| webhooks.endpoints.create | POST /v1/webhook-endpoints | Create a webhook endpoint. The signing secret is returned once, in this response. | webhooks:manage |
| webhooks.endpoints.get | GET /v1/webhook-endpoints/{endpoint_id} | One webhook endpoint. | webhooks:manage |
| webhooks.endpoints.update | PATCH /v1/webhook-endpoints/{endpoint_id} | Change a webhook endpoint. Only the fields sent change. | webhooks:manage |
| webhooks.endpoints.delete | DELETE /v1/webhook-endpoints/{endpoint_id} | Delete a webhook endpoint and its delivery log. | webhooks:manage |
| webhooks.deliveries.list | GET /v1/webhook-endpoints/{endpoint_id}/deliveries | One endpoint's deliveries, newest first. No payloads. | webhooks:manage |
| webhooks.endpoints.rotate_secret | POST /v1/webhook-endpoints/{endpoint_id}/rotate-secret | A new signing secret, returned once. The previous one keeps co-signing for 24 hours. | webhooks:manage |
| webhooks.endpoints.test | POST /v1/webhook-endpoints/{endpoint_id}/test | Queue one test.ping to this endpoint, whatever it subscribes to. | webhooks:manage |
| webhooks.events.list | GET /v1/webhook-events | Every event type an endpoint can subscribe to. | webhooks:manage |
Discovery
| Operation | Method and path | Summary | Scopes |
|---|---|---|---|
| discovery.balance | GET /v1/discovery/balance | The organization's discovery token balance. | discovery:read |
| discovery.handles.resolve | POST /v1/discovery/handles/resolve | Resolve Instagram handles to accounts, to use as a recipe's seeds. | discovery:spend |
| discovery.icp_profiles.list | GET /v1/discovery/icp-profiles | The organization's customer profiles (ICP), each at its newest version. | discovery:read |
| discovery.modes | GET /v1/discovery/modes | The discovery modes and what this deployment can run. | discovery:read |
| discovery.quote | POST /v1/discovery/quote | Price a recipe in tokens without saving or starting anything. | discovery:read |
| discovery.recipes.create | POST /v1/discovery/recipes | Save a search recipe. | discovery:spend |
| discovery.runs.list | GET /v1/discovery/runs | The workspace's runs, newest first. | discovery:read |
| discovery.runs.create | POST /v1/discovery/runs | Start a discovery run: price the recipe, reserve its tokens and queue it. | discovery:spend |
| discovery.runs.get | GET /v1/discovery/runs/{run_id} | One run, with its live activity. Poll every 10 seconds while it moves. | discovery:read |
| discovery.runs.cancel | POST /v1/discovery/runs/{run_id}/cancel | Cancel a run that is still moving and release its unspent tokens. | discovery:spend |
| discovery.candidates.list | GET /v1/discovery/runs/{run_id}/candidates | A run's results, in its delivery order. | discovery:read |
| discovery.runs.preview_decision | POST /v1/discovery/runs/{run_id}/preview-decision | Answer a run's preview: continue spending its reservation, or stop and release it. | discovery:spend |
| discovery.candidates.promote | POST /v1/discovery/runs/{run_id}/promote | Move a run's results into the CRM as leads. | discovery:read, leads:write |
AI Setter
| Operation | Method and path | Summary | Scopes |
|---|---|---|---|
| setter.knowledge.list | GET /v1/reps/{rep_id}/setter/knowledge | List a rep's AI Setter knowledge entries, oldest first. | setter:read |
| setter.knowledge.create | POST /v1/reps/{rep_id}/setter/knowledge | Add a knowledge entry the rep's AI Setter may answer from. | setter:write |
| setter.booking.preview | GET /v1/setter/booking-preview | The free meeting times a variant's saved booking rules would offer a new prospect right now. | setter:read |
| setter.connections.get | GET /v1/setter/connections | Whether the workspace's Google Calendar and Calendly are connected, for the setter's booking goal. | setter:read |
| setter.knowledge.update | PATCH /v1/setter/knowledge/{knowledge_id} | Change a knowledge entry's title, content, or both. | setter:write |
| setter.knowledge.delete | DELETE /v1/setter/knowledge/{knowledge_id} | Delete a knowledge entry. | setter:write |
| setter.persona.get | GET /v1/setter/persona | Read the persona (name, role, tone, style, language) of one or more reps. | setter:read |
| setter.persona.set | PUT /v1/setter/persona | Write persona fields onto the live setter variant of each named rep. | setter:write |
| setter.test | POST /v1/setter/test | Run the AI Setter on a typed thread with an inline configuration and get its next reply. | setter:write |
Setter
| Operation | Method and path | Summary | Scopes |
|---|---|---|---|
| setter.variants.list | GET /v1/reps/{rep_id}/setter/variants | List a rep's AI Setter variants, newest first. | setter:read |
| setter.variants.create | POST /v1/reps/{rep_id}/setter/variants | Create a draft AI Setter variant for a rep. | setter:write |
| setter.variants.get | GET /v1/setter/variants/{variant_id} | Read one AI Setter variant, any status. | setter:read |
| setter.variants.update | PATCH /v1/setter/variants/{variant_id} | Change any field of an AI Setter variant. | setter:write |
| setter.variants.archive | POST /v1/setter/variants/{variant_id}/archive | Retire a variant, or stop its A/B test. | setter:write |
| setter.variants.promote | POST /v1/setter/variants/{variant_id}/promote | End the rep's A/B test with this variant as the winner. | setter:write |
| setter.variants.publish | POST /v1/setter/variants/{variant_id}/publish | Make a variant the rep's live variant. | setter:write |
| setter.variants.start_test | POST /v1/setter/variants/{variant_id}/start-test | Put a variant into the rep's A/B test as a challenger. | setter:write |
| setter.variants.versions.list | GET /v1/setter/variants/{variant_id}/versions | List a variant's earlier contents, newest version first. | setter:read |
Meta
| Operation | Method and path | Summary | Scopes |
|---|---|---|---|
| meta.openapi | GET /v1/openapi.json | The OpenAPI 3.1 document of this API. | public |