API Reference

Programmatic access to OutreachPilot. Import contacts, trigger campaigns, chat with PilotPlus AI, and receive event webhooks. Designed for AI agents and automation platforms.

Learning Center

New

Master the platform with comprehensive video walkthroughs and step-by-step feature guides.

Getting Started

1

Upgrade to Pro

API access requires a Pro or Scale plan. Go to Settings → Billing.

2

Create an API Key

Go to Settings → Workspace → Developer API. Copy your key — it's shown once.

3

Make Requests

Send requests with Authorization: Bearer op_live_xxx

Authentication

All requests require an API key passed as a Bearer token:

curl -H "Authorization: Bearer op_live_YOUR_KEY" \
  https://app.outreachpilot.com/api/v1/credits
⚠️

Keep your API key secret. Do not expose it in client-side code or public repositories.

Keys are hashed with SHA-256 and cannot be recovered. If compromised, revoke immediately and create a new one.

Response Format

Every response follows a consistent format with machine-readable metadata:

Success
{
  "ok": true,
  "data": { ... },
  "meta": {
    "request_id": "req_abc123",
    "timestamp": "2026-03-08T...",
    "credits_used": 1,
    "credits_remaining": 4832
  }
}
Error
{
  "ok": false,
  "error": {
    "code": "INVALID_API_KEY",
    "message": "Human-readable message",
    "details": "Diagnostic info...",
    "docs_url": "/docs#invalid_api_key"
  },
  "meta": {
    "request_id": "req_abc123",
    "timestamp": "2026-03-08T..."
  }
}

Contacts

Import, export, and manage CRM contacts.

GET/api/v1/contactsscope: contacts · free

List contacts with pagination and filtering.

Query Parameters

limit (max 200), offset, status, folder_id, search

Response

{ ok: true, data: Contact[], meta: { total, has_more, limit, offset } }

Example (cURL)

curl -H "Authorization: Bearer op_live_YOUR_KEY" \
  "https://app.outreachpilot.com/api/v1/contacts?limit=50&search=john"
POST/api/v1/contactsscope: contacts · free

Create one or many contacts. Supports upsert.

Request Body

{ email, first_name?, last_name?, company?, title?, linkedin_url?, upsert?: true } or { contacts: [...], upsert?: true }

Response

{ ok: true, data: { contacts: Contact[], count: number } }

Example (cURL)

curl -X POST -H "Authorization: Bearer op_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email":"john@acme.com","first_name":"John","company":"Acme"}' \
  "https://app.outreachpilot.com/api/v1/contacts"
GET/api/v1/contacts/:idscope: contacts · free

Get a single contact by ID.

Response

{ ok: true, data: Contact }

Example (cURL)

curl -H "Authorization: Bearer op_live_YOUR_KEY" \
  "https://app.outreachpilot.com/api/v1/contacts/CONTACT_UUID"
PUT/api/v1/contacts/:idscope: contacts · free

Update a contact. Only provided fields are changed.

Request Body

{ first_name?, last_name?, email?, company?, title?, status?, ... }

Response

{ ok: true, data: Contact }

Example (cURL)

curl -X PUT -H "Authorization: Bearer op_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"title":"VP of Sales"}' \
  "https://app.outreachpilot.com/api/v1/contacts/CONTACT_UUID"
DELETE/api/v1/contacts/:idscope: contacts · free

Delete a contact permanently.

Response

{ ok: true, data: { deleted: true, id: "..." } }

Example (cURL)

curl -X DELETE -H "Authorization: Bearer op_live_YOUR_KEY" \
  "https://app.outreachpilot.com/api/v1/contacts/CONTACT_UUID"

Companies

Manage companies (Accounts). Contacts are automatically linked to these when domains match.

GET/api/v1/companiesscope: contacts · free

List companies with pagination and filtering.

Query Parameters

limit (max 200), offset, search, domain

Response

{ ok: true, data: Company[], meta: { total, has_more, limit, offset } }

Example (cURL)

curl -H "Authorization: Bearer op_live_YOUR_KEY" \
  "https://app.outreachpilot.com/api/v1/companies?domain=acme.com"
POST/api/v1/companiesscope: contacts · free

Create or update companies. Any unrecognized fields are stored in "context".

Request Body

{ name?, domain?, industry?, size?, upsert?: true } or { companies: [...], upsert?: true }

Response

{ ok: true, data: { companies: Company[], count: number } }

Example (cURL)

curl -X POST -H "Authorization: Bearer op_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Acme Corp","domain":"acme.com","industry":"Software"}' \
  "https://app.outreachpilot.com/api/v1/companies"
GET/api/v1/companies/:idscope: contacts · free

Get a single company by ID.

Response

{ ok: true, data: Company }
PUT/api/v1/companies/:idscope: contacts · free

Update a company. Only provided fields are changed. Custom properties go into context.

Request Body

{ name?, domain?, industry?, size?, ... }

Response

{ ok: true, data: Company }
DELETE/api/v1/companies/:idscope: contacts · free

Delete a company. Linked contacts will have their account_id set to null automatically.

Response

{ ok: true, data: { deleted: true, id: "..." } }

AI Chat

Interact with the PilotPlus AI engine. Full tool access: research, draft messages, manage contacts, trigger campaigns.

POST/api/v1/chatscope: chat · 1 credit

Send a message to PilotPlus AI. Non-streaming JSON response. The AI can execute tools (research, drafting, CRM operations) autonomously.

Request Body

{ message: string, thread_id?: string }

Response

{ ok: true, data: { response: string, thread_id: string?, tool_calls: [...], model: string, usage: { input_tokens, output_tokens } } }

Example (cURL)

curl -X POST -H "Authorization: Bearer op_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"message":"Find me 10 VP-level fintech contacts in NYC"}' \
  "https://app.outreachpilot.com/api/v1/chat"

Credits

Check your credit balance and plan information.

GET/api/v1/creditsscope: credits · free

Get current credit balance, plan tier, and reset date.

Response

{ ok: true, data: { credits_remaining, credits_monthly, plan_tier, credits_reset_at } }

Example (cURL)

curl -H "Authorization: Bearer op_live_YOUR_KEY" \
  "https://app.outreachpilot.com/api/v1/credits"

Campaigns

Trigger campaigns and check their status.

POST/api/v1/campaigns/:id/triggerscope: campaigns · free

Add a contact to a campaign. Provide contact_id or contact fields (auto-creates if new).

Request Body

{ contact_id: string } or { email, first_name?, last_name?, company? }

Response

{ ok: true, data: { triggered: true, campaign_id, contact_id } }

Example (cURL)

curl -X POST -H "Authorization: Bearer op_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email":"john@acme.com","first_name":"John"}' \
  "https://app.outreachpilot.com/api/v1/campaigns/CAMPAIGN_UUID/trigger"
GET/api/v1/campaigns/:id/statusscope: campaigns · free

Get campaign status with audience breakdown.

Response

{ ok: true, data: { campaign_id, name, status, audience: { total, active, completed, paused, bounced, failed } } }

Example (cURL)

curl -H "Authorization: Bearer op_live_YOUR_KEY" \
  "https://app.outreachpilot.com/api/v1/campaigns/CAMPAIGN_UUID/status"

Webhooks

Subscribe to real-time event notifications.

GET/api/v1/webhooksscope: campaigns · free

List active webhook subscriptions.

Response

{ ok: true, data: { webhooks: [...], available_events: [...] } }
POST/api/v1/webhooksscope: campaigns · free

Register a webhook URL for events.

Request Body

{ url: "https://...", events: ["email.opened", "campaign.completed"], secret?: "hmac_secret" }

Response

{ ok: true, data: WebhookSubscription }
DELETE/api/v1/webhooks?id=xxxscope: campaigns · free

Deactivate a webhook subscription.

Response

{ ok: true, data: { deleted: true } }

Error Codes

All errors include a machine-readable code, message, and details for diagnostics.

CodeHTTPWhen
MISSING_AUTH401No Authorization header provided
INVALID_API_KEY401Key not found, revoked, or malformed
PLAN_REQUIRED403Organization not on Pro or Scale plan
SCOPE_DENIED403API key missing required scope for this endpoint
ORG_NOT_FOUND404Organization deleted or invalid
RESOURCE_NOT_FOUND404Contact, campaign, or webhook not found
VALIDATION_ERROR422Invalid request body or missing required fields
DUPLICATE_RESOURCE409Resource already exists (e.g. contact email)
INSUFFICIENT_CREDITS402Not enough credits for the operation
CAMPAIGN_NOT_ACTIVE400Campaign is draft or paused
INTERNAL_ERROR500Unexpected server error

Rate Limits & Credits

Rate limiting is managed through credits. Each operation has a credit cost (most are free). AI Chat costs 1-2 credits per message depending on the model.

When your credits run out, API calls that require credits will return INSUFFICIENT_CREDITS (402). Check your balance anytime at GET /api/v1/credits.

Credits reset monthly on your billing date. Monitor usage in Settings → Usage.

© 2026 OutreachPilot · Home · Sign In