Download OpenAPI specification:
Workspace-scoped automation for FlowSender campaigns and leads.
The FlowSender external API is a server-to-server interface pending its first production release. A workspace administrator creates a named API key in the Developer page; the raw secret is displayed only once. Never embed a key in browser or mobile code, paste it into a documentation site, or log it. Send it only to FlowSender over HTTPS.
The API key determines the workspace. Requests cannot select or override workspace_id.
API keys work only on the documented /api/v1 routes and are rejected by the browser-session
/api surface. Browser sessions are rejected by /api/v1.
API v1 permits additive endpoints and optional fields. Removing or renaming an endpoint or
field, changing its type or meaning, tightening accepted validation, or changing authentication
is breaking and requires a new path-major. A deprecated major is supported for at least 180
days and returns Deprecation, Sunset, and migration-guide Link headers. FlowSender supports
at most two majors concurrently unless a documented, time-bounded exception applies.
Collection cursors are opaque, signed, filter-bound, and valid for 24 hours. Do not parse them.
Restart without a cursor after cursor_expired. Every response includes X-Request-ID.
Returns campaigns ordered by created_at DESC, id DESC within the key's workspace.
| limit | integer [ 1 .. 100 ] Default: 50 Page size; defaults to 50 and cannot exceed 100. |
| cursor | string non-empty Opaque cursor from the previous page, valid for 24 hours and bound to filters and order. |
| status | string (CampaignStatus) Enum: "draft" "active" "paused" "archived" Filter by campaign status. |
| q | string <= 200 characters Case-insensitive campaign-name search. |
{- "data": [
- {
- "id": 44,
- "name": "Product leaders — August",
- "status": "active",
- "daily_send_cap": 80,
- "interval_min_seconds": 75,
- "interval_max_seconds": 180,
- "created_at": "2026-08-16T18:30:00Z",
- "stats": {
- "enrollments_total": 18,
- "enrollments_active": 14,
- "enrollments_paused": 0,
- "enrollments_completed": 2,
- "enrollments_replied": 1,
- "enrollments_bounced": 1,
- "emails_sent": 31
}
}
], - "page": {
- "next_cursor": "string",
- "has_more": true
}
}Returns campaign configuration, status, and aggregate enrollment and send counts.
| campaign_id required | integer <int64> >= 1 Workspace campaign identifier. |
{- "data": {
- "id": 44,
- "name": "Product leaders — August",
- "status": "active",
- "daily_send_cap": 80,
- "interval_min_seconds": 75,
- "interval_max_seconds": 180,
- "created_at": "2026-08-16T18:30:00Z",
- "stats": {
- "enrollments_total": 18,
- "enrollments_active": 14,
- "enrollments_paused": 0,
- "enrollments_completed": 2,
- "enrollments_replied": 1,
- "enrollments_bounced": 1,
- "emails_sent": 31
}
}
}Returns steps ordered by step_index ASC, id ASC.
| campaign_id required | integer <int64> >= 1 Workspace campaign identifier. |
| limit | integer [ 1 .. 100 ] Default: 50 Page size; defaults to 50 and cannot exceed 100. |
| cursor | string non-empty Opaque cursor from the previous page, valid for 24 hours and bound to filters and order. |
{- "data": [
- {
- "id": 0,
- "campaign_id": 0,
- "step_index": 0,
- "subject_template": "string",
- "body_template": "string",
- "delay_days": 0,
- "created_at": "2026-08-16T18:30:00Z",
- "updated_at": "2026-08-16T18:30:00Z"
}
], - "page": {
- "next_cursor": "string",
- "has_more": true
}
}Returns enrollments ordered by enrollment creation time descending, then ID descending.
| campaign_id required | integer <int64> >= 1 Workspace campaign identifier. |
| limit | integer [ 1 .. 100 ] Default: 50 Page size; defaults to 50 and cannot exceed 100. |
| cursor | string non-empty Opaque cursor from the previous page, valid for 24 hours and bound to filters and order. |
| status | string (EnrollmentStatus) Enum: "active" "paused" "replied" "completed" "bounced" Filter by enrollment status. |
| mailbox_provider_family | string Enum: "google" "microsoft" "yahoo" "custom" "unknown" Filter by detected mailbox-provider family. |
| q | string <= 200 characters Search lead email or custom fields. |
{- "data": [
- {
- "lead_id": 0,
- "email": "user@example.com",
- "lead_status": "active",
- "fields": { },
- "mailbox_provider": {
- "family": "google",
- "provider": "string",
- "confidence": 100,
- "evidence": "string",
- "detected_at": "2026-08-16T18:30:00Z",
- "refreshed_at": "2026-08-16T18:30:00Z"
}, - "enrollment_id": 0,
- "campaign_id": 0,
- "current_step_index": 0,
- "enrollment_status": "active",
- "next_send_at": "2026-08-16T18:30:00Z",
- "last_contacted_at": "2026-08-16T18:30:00Z",
- "enrolled_at": "2026-08-16T18:30:00Z",
- "enrollment_updated_at": "2026-08-16T18:30:00Z"
}
], - "page": {
- "next_cursor": "string",
- "has_more": true
}
}Returns enrollments ordered by enrollment creation time descending, then ID descending.
| campaign_id required | integer <int64> >= 1 Workspace campaign identifier. |
| limit | integer [ 1 .. 100 ] Default: 50 Page size; defaults to 50 and cannot exceed 100. |
| cursor | string non-empty Opaque cursor from the previous page, valid for 24 hours and bound to filters and order. |
| status | string (EnrollmentStatus) Enum: "active" "paused" "replied" "completed" "bounced" Filter by enrollment status. |
| mailbox_provider_family | string Enum: "google" "microsoft" "yahoo" "custom" "unknown" Filter by detected mailbox-provider family. |
| q | string <= 200 characters Search lead email or custom fields. |
{- "data": [
- {
- "lead_id": 0,
- "email": "user@example.com",
- "lead_status": "active",
- "fields": { },
- "mailbox_provider": {
- "family": "google",
- "provider": "string",
- "confidence": 100,
- "evidence": "string",
- "detected_at": "2026-08-16T18:30:00Z",
- "refreshed_at": "2026-08-16T18:30:00Z"
}, - "enrollment_id": 0,
- "campaign_id": 0,
- "current_step_index": 0,
- "enrollment_status": "active",
- "next_send_at": "2026-08-16T18:30:00Z",
- "last_contacted_at": "2026-08-16T18:30:00Z",
- "enrolled_at": "2026-08-16T18:30:00Z",
- "enrollment_updated_at": "2026-08-16T18:30:00Z"
}
], - "page": {
- "next_cursor": "string",
- "has_more": true
}
}Returns leads ordered by created_at DESC, id DESC; message history is omitted.
| limit | integer [ 1 .. 100 ] Default: 50 Page size; defaults to 50 and cannot exceed 100. |
| cursor | string non-empty Opaque cursor from the previous page, valid for 24 hours and bound to filters and order. |
| status | string (LeadStatus) Enum: "active" "replied" "bounced" Filter by lead status. |
| mailbox_provider_family | string Enum: "google" "microsoft" "yahoo" "custom" "unknown" Filter by detected mailbox-provider family. |
| q | string <= 200 characters Search lead email or custom fields. |
{- "data": [
- {
- "id": 101,
- "email": "ada@example.test",
- "status": "active",
- "fields": {
- "first_name": "Ada",
- "company": "Analytical Engines"
}, - "mailbox_provider": {
- "family": "custom",
- "provider": "example.test",
- "confidence": 80
}, - "enrollments_total": 1,
- "created_at": "2026-08-16T18:30:00Z"
}
], - "page": {
- "next_cursor": "string",
- "has_more": true
}
}Returns lead and enrollment data; unibox and message history are intentionally omitted.
| lead_id required | integer <int64> >= 1 Workspace lead identifier. |
{- "data": {
- "lead": {
- "id": 101,
- "email": "ada@example.test",
- "status": "active",
- "fields": {
- "first_name": "Ada",
- "company": "Analytical Engines"
}, - "mailbox_provider": {
- "family": "custom",
- "provider": "example.test",
- "confidence": 80
}, - "enrollments_total": 1,
- "created_at": "2026-08-16T18:30:00Z"
}, - "enrollments": [
- {
- "id": 0,
- "campaign_id": 0,
- "campaign_name": "string",
- "current_step_index": 0,
- "status": "active",
- "next_send_at": "2026-08-16T18:30:00Z",
- "last_sent_at": "2026-08-16T18:30:00Z",
- "created_at": "2026-08-16T18:30:00Z",
- "updated_at": "2026-08-16T18:30:00Z"
}
]
}
}Imports leads from JSON or CSV and omits FlowSender's internal object-storage key. This
operation requires Idempotency-Key. Equivalent canonical JSON, or multipart requests
with equivalent fields and file bytes, share a fingerprint regardless of JSON object order,
multipart boundary, field order, or filename. Completed 2xx and deterministic 4xx
responses replay for 24 hours. 408, 429, and 5xx are not cached. Reuse for different
content returns idempotency_key_reused; concurrent duplicates return
idempotency_in_progress.
| Idempotency-Key required | string [ 8 .. 255 ] characters ^[ -~]+$ Example: 018f8f5e-6c4a-7d27-a6f1-fake12345678 New 8–255 character printable ASCII value for each intended operation, retained for 24 hours. |
object | |
required | Array of objects non-empty |
{- "mapping": {
- "email": "email",
- "first_name": "first_name"
}, - "rows": [
- {
- "email": "ada@example.test",
- "first_name": "Ada"
}
]
}{- "data": {
- "imported": 0,
- "failed": 0,
- "rows": [
- {
- "line": 1,
- "email": "user@example.com",
- "lead_id": 0,
- "error": "string"
}
]
}
}Returns totals, daily buckets, and campaign summaries for an inclusive UTC date range.
| from required | string <date> First date in the inclusive UTC range. |
| to required | string <date> Last date in the inclusive UTC range. |
| campaign_id | integer <int64> >= 1 Restrict results to one campaign. |
{- "data": {
- "from": "2019-08-24",
- "to": "2019-08-24",
- "campaign_id": 0,
- "summary": {
- "sent_count": 0,
- "reply_count": 0,
- "bounce_count": 0,
- "reply_rate": 1,
- "bounce_rate": 1
}, - "daily": [
- {
- "sent_count": 0,
- "reply_count": 0,
- "bounce_count": 0,
- "reply_rate": 1,
- "bounce_rate": 1,
- "day": "2019-08-24"
}
], - "campaigns": [
- {
- "sent_count": 0,
- "reply_count": 0,
- "bounce_count": 0,
- "reply_rate": 1,
- "bounce_rate": 1,
- "campaign_id": 0,
- "campaign_name": "string"
}
]
}
}Enrolls existing leads transactionally and requires Idempotency-Key.
| campaign_id required | integer <int64> >= 1 Workspace campaign identifier. |
| Idempotency-Key required | string [ 8 .. 255 ] characters ^[ -~]+$ Example: 018f8f5e-6c4a-7d27-a6f1-fake12345678 New 8–255 character printable ASCII value for each intended operation, retained for 24 hours. |
| lead_ids required | Array of integers <int64> [ 1 .. 500 ] items unique [ items <int64 > >= 1 ] |
{- "lead_ids": [
- 101,
- 102
]
}{- "data": {
- "enrollments": [
- {
- "id": 0,
- "campaign_id": 0,
- "lead_id": 0,
- "current_step_index": 0,
- "status": "active",
- "next_send_at": "2026-08-16T18:30:00Z",
- "created_at": "2026-08-16T18:30:00Z",
- "updated_at": "2026-08-16T18:30:00Z"
}
]
}
}Receiver-side contract example for an inbound lead reply.
| X-FlowSender-Delivery-ID required | string <uuid> Stable logical-delivery UUID, unchanged across retries and suitable for deduplication. |
| X-FlowSender-Event required | string (EventName) Enum: "reply_received" "step_sent" "bounce_detected" "enrollment_completed" Event name matching the envelope. |
| X-FlowSender-Timestamp required | integer <int64> Unix seconds regenerated for every attempt; reject timestamps more than five minutes old. |
| X-FlowSender-Signature required | string^v1=[0-9a-f]{64}(,v1=[0-9a-f]{64})?$ One or two comma-separated |
| id required | string <uuid> Stable across delivery retries. |
| version required | integer Value: 1 |
| event required | string Enum: "reply_received" "step_sent" "bounce_detected" "enrollment_completed" Value: "reply_received" |
| occurred_at required | string <date-time> |
| workspace_id required | integer <int64> |
required | object |
{- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "version": 1,
- "event": "reply_received",
- "occurred_at": "2019-08-24T14:15:22Z",
- "workspace_id": 0,
- "data": {
- "lead_id": 0,
- "campaign_id": 0,
- "message_id": "string",
- "from": "user@example.com",
- "subject": "string",
- "body_preview": "string"
}
}Receiver-side contract example for an email step sent by FlowSender.
| X-FlowSender-Delivery-ID required | string <uuid> Stable logical-delivery UUID, unchanged across retries and suitable for deduplication. |
| X-FlowSender-Event required | string (EventName) Enum: "reply_received" "step_sent" "bounce_detected" "enrollment_completed" Event name matching the envelope. |
| X-FlowSender-Timestamp required | integer <int64> Unix seconds regenerated for every attempt; reject timestamps more than five minutes old. |
| X-FlowSender-Signature required | string^v1=[0-9a-f]{64}(,v1=[0-9a-f]{64})?$ One or two comma-separated |
| id required | string <uuid> Stable across delivery retries. |
| version required | integer Value: 1 |
| event required | string Enum: "reply_received" "step_sent" "bounce_detected" "enrollment_completed" Value: "step_sent" |
| occurred_at required | string <date-time> |
| workspace_id required | integer <int64> |
required | object |
{- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "version": 1,
- "event": "step_sent",
- "occurred_at": "2019-08-24T14:15:22Z",
- "workspace_id": 0,
- "data": {
- "lead_id": 0,
- "campaign_id": 0,
- "step_index": 0,
- "inbox_id": 0,
- "message_id": "string"
}
}Receiver-side contract example for a detected delivery bounce.
| X-FlowSender-Delivery-ID required | string <uuid> Stable logical-delivery UUID, unchanged across retries and suitable for deduplication. |
| X-FlowSender-Event required | string (EventName) Enum: "reply_received" "step_sent" "bounce_detected" "enrollment_completed" Event name matching the envelope. |
| X-FlowSender-Timestamp required | integer <int64> Unix seconds regenerated for every attempt; reject timestamps more than five minutes old. |
| X-FlowSender-Signature required | string^v1=[0-9a-f]{64}(,v1=[0-9a-f]{64})?$ One or two comma-separated |
| id required | string <uuid> Stable across delivery retries. |
| version required | integer Value: 1 |
| event required | string Enum: "reply_received" "step_sent" "bounce_detected" "enrollment_completed" Value: "bounce_detected" |
| occurred_at required | string <date-time> |
| workspace_id required | integer <int64> |
required | object |
{- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "version": 1,
- "event": "bounce_detected",
- "occurred_at": "2019-08-24T14:15:22Z",
- "workspace_id": 0,
- "data": {
- "lead_id": 0,
- "campaign_id": 0,
- "inbox_id": 0,
- "error": "string"
}
}Receiver-side contract example for completion of every campaign step.
| X-FlowSender-Delivery-ID required | string <uuid> Stable logical-delivery UUID, unchanged across retries and suitable for deduplication. |
| X-FlowSender-Event required | string (EventName) Enum: "reply_received" "step_sent" "bounce_detected" "enrollment_completed" Event name matching the envelope. |
| X-FlowSender-Timestamp required | integer <int64> Unix seconds regenerated for every attempt; reject timestamps more than five minutes old. |
| X-FlowSender-Signature required | string^v1=[0-9a-f]{64}(,v1=[0-9a-f]{64})?$ One or two comma-separated |
| id required | string <uuid> Stable across delivery retries. |
| version required | integer Value: 1 |
| event required | string Enum: "reply_received" "step_sent" "bounce_detected" "enrollment_completed" Value: "enrollment_completed" |
| occurred_at required | string <date-time> |
| workspace_id required | integer <int64> |
required | object |
{- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "version": 1,
- "event": "enrollment_completed",
- "occurred_at": "2019-08-24T14:15:22Z",
- "workspace_id": 0,
- "data": {
- "lead_id": 0,
- "campaign_id": 0,
- "enrollment_id": 0
}
}