Skip to content
Pathbound DOCS

Agents API

Agents are AI workers that monitor contacts matching a filter, analyze their activity, and propose actions. Each agent has a playbook (a markdown prompt) that defines its reasoning, plus capabilities, monitoring config, and an LLM config.

GET /v1/agents

Required scope: agents:read

ParameterTypeDefaultDescription
enabledbooleanFilter by enabled/disabled status.
playbook_templatestringFilter by playbook template.
limitnumber20Results per page (1–100).
offsetnumber0Pagination offset.
{
"status": "success",
"agents": [ /* agent objects */ ],
"total": 5,
"limit": 20,
"offset": 0
}

POST /v1/agents

Required scope: agents:write

FieldTypeRequiredDescription
namestringyesAgent display name.
descriptionstringnoHuman-readable description.
playbook_templatestringnoPredefined template (e.g. cold_outreach, pricing_visitor_followup).
playbookobjectnoCustom playbook — { playbook_md: "..." } plus optional structured config.
capabilitiesstring[]noAllowed capabilities (e.g. email, linkedin, notes, crm_sync).
identity_idstringnoDefault identity used for outreach actions.
monitoringobjectno{ filter, schedule_cron, max_contacts_per_run } — who/when to monitor.
llm_configobjectno{ provider, model, temperature, max_tokens }.
enabledbooleannoWhether the agent is active (default: false).

Example — minimal agent with a custom playbook

Section titled “Example — minimal agent with a custom playbook”
Terminal window
curl -X POST https://api.pathbound.ai/v1/agents \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Pricing visitor follow-up",
"description": "Drafts a personal email when a contact visits /pricing twice in 7 days.",
"playbook": {
"playbook_md": "You are an SDR. For each contact, look at their recent events. If they visited /pricing 2+ times in the last 7 days and have not received an email from us in the last 3 days, propose a short, personal follow-up email referencing what they did on the site. Keep it under 80 words. If conditions are not met, propose no action."
},
"capabilities": ["email"],
"identity_id": "id_123",
"monitoring": {
"filter": { "lifecycle_stage": "lead" },
"schedule_cron": "0 14 * * 1-5",
"max_contacts_per_run": 25
},
"llm_config": { "provider": "anthropic", "model": "claude-opus-4-7", "temperature": 0.4 },
"enabled": true
}'
{
"status": "success",
"agent": { /* agent object */ }
}

GET /v1/agents/:id

Required scope: agents:read


PATCH /v1/agents/:id

Required scope: agents:write

Send only the fields you want to update. To revise just the playbook prompt, send { "playbook": { "playbook_md": "..." } }.


DELETE /v1/agents/:id

Required scope: agents:write

Deleting an agent also removes its associated runs.


POST /v1/agents/:id/trigger

Required scope: agents:trigger

Manually trigger a run, optionally targeting specific contacts.

FieldTypeRequiredDescription
contact_idsstring[]noSpecific contacts to target. If omitted, the agent uses its monitoring filter.
{
"status": "success",
"job_id": "job_xyz789"
}

The run is enqueued for asynchronous execution. Poll with GET /v1/agents/:id/runs to see when it completes.


GET /v1/agents/:id/runs

Required scope: agents:read

ParameterTypeDefaultDescription
limitnumber20Results per page (1–100).
offsetnumber0Pagination offset.
statusstringFilter by run status.

GET /v1/agents/runs/:runId

Required scope: agents:read

ParameterTypeDefaultDescription
modestringfullsummary (counts + status only) or full (per-contact results).

In full mode, the response is capped at 25 contacts and includes proposed actions per contact, each addressed by (run_id, contact_id, action_index) for approval.

{
"status": "success",
"run": {
"_id": "run_abc",
"agent_id": "ag_123",
"status": "completed",
"started_at": "...",
"completed_at": "...",
"summary": {
"contacts_evaluated": 42,
"actions_proposed": 18,
"actions_auto_approved": 6,
"actions_pending_approval": 12,
"errors": 0
}
}
}
{
"status": "success",
"run": {
"_id": "run_abc",
"agent_id": "ag_123",
"status": "completed",
"summary": { /* same as above */ },
"contact_results": [
{
"contact_id": "ct_abc",
"contact": { "email": "...", "firstname": "..." },
"reasoning": "Visited /pricing 3 times this week, no email in 5 days...",
"proposed_actions": [
{
"type": "email_message",
"params": { "subject": "...", "message": "..." },
"status": "pending_approval"
}
]
}
]
}
}

POST /v1/agents/runs/:runId/contacts/:contactId/actions/:actionIndex/approve

Required scope: agents:approve

Approves a single action proposed in a run. The action is then queued for execution.


POST /v1/agents/runs/:runId/contacts/:contactId/actions/:actionIndex/reject

Required scope: agents:approve

Rejects a single proposed action. It will not execute.


Playbooks are markdown prompts that define the agent’s reasoning. They are sent to the LLM with structured context about each contact. A few patterns that work well:

  • Be explicit about what to skip. “If the contact has not had a pageview in 14 days, propose no action.”
  • Constrain the action shape. “Keep emails under 80 words. Always reference a specific event in their timeline.”
  • Use the structured fields when possible. Agents have access to events, unified_profile, recent_actions — instruct the playbook to reason from those before generating output.
  • Set require_approval: true for outbound actions until you trust the agent. Auto-approval is convenient but cannot be undone after execution.

For approval at scale, prefer the agent run approval endpoints over per-action endpoints — they share state (run_id) and let you bulk-approve a run from your UI.