Generate Batch (multiple leads)
Generate Batch (multiple leads)
Generate personalized cold email sequences for multiple leads in one request. The API accepts the batch and returns immediately with a list_id. Processing runs asynchronously; you poll the list status and then export results when completed.
POST /api/v1/campaigns/:id/generate-batch · scope campaigns:write
You can submit a batch before the build finishes. As soon as value propositions are selected, the campaign is eligible for generation — you do not need to wait for build-status
overallto reachready. Batches submitted while the build is still in progress (overall: "building") are accepted and queued; processing begins automatically once the build completes. Submitting before value propositions are selected returns400 BAD_REQUEST(campaign setup incomplete).
Path parameters
| Parameter | Type | Description |
|---|---|---|
id | string (UUID) | Campaign ID (from GET /api/v1/campaigns). |
Headers
| Header | Required | Description |
|---|---|---|
Authorization or X-API-Key | Yes | API key. |
Content-Type | Yes | application/json |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
leads | array | Yes | Array of lead objects (at least one). Each lead must include a valid email. |
leads[].name | string | No | Full name. |
leads[].title | string | No | Job title. |
leads[].company | string | No | Company name. |
leads[].email | string | Yes | Email (required; used for mapping and export). |
leads[].linkedin_url | string | No | LinkedIn profile URL. |
leads[].company_website | string | No | Company website. |
options | object | Yes | Generation configuration (see fields below). email_count and a signature are required. |
options.email_count | number | Yes | Emails to generate per lead. Integer 1–4. |
options.email_signature | string | Yes* | Sender signature, inline. Required unless signature_id is provided. Multi-line: use \n between lines. See Signature format below. |
options.signature_id | string (UUID) | Yes* | ID of a saved signature (from GET /api/v1/signatures) to use instead of email_signature. Provide exactly one of email_signature or signature_id. |
options.list_name | string | No | Display name for the generated list. Defaults to API Batch (N leads). |
options.enrichment_enabled | boolean | No | When true, runs web research per lead before writing (each lead costs 2 credits instead of 1). Requires an enrichment signal on every lead — see Enrichment requirements. |
options.notification_email | string | No | Email address to receive the "processing complete" notification (with a link to the processed list). Must be a valid email. If omitted, the notification is sent to the workspace owner. |
options.additional_details | string | No | Free-text campaign context passed to the writer ("Added Campaign Details") — angle, constraints, or instructions that override defaults. |
options.approved_ctas | string[] | string | No | CTA types to use. Defaults to Question CTA, Lead Magnet CTA, Direct Meeting CTA. |
* Exactly one of email_signature or signature_id is required (providing both is a 400).
Note:
campaign_angleis a deprecated alias ofadditional_details, andsequence_nameis a deprecated alias oflist_name. Prefer the new names.
Completion notifications. When a batch finishes processing in the background, MachFive sends a "processing complete" email containing a link to the processed list. By default this goes to the workspace owner. Set
options.notification_emailto send it to a different address instead. (The single-lead generate endpoint returns results synchronously in the response and does not send a notification email.)
Signature format
The signature is required so the writer never fabricates sender details. Send it
as a single string with \n line breaks; each line is rendered on its own line in
the email. Best-practice cold-email structure:
Name
Company Name | Position
Company Address
As JSON:
"email_signature": "Jane Doe\nAcme Inc | VP Marketing\n123 Main St, Springfield, IL 62701"To reuse a saved signature instead, omit email_signature and pass
signature_id (manage saved signatures via Signatures):
"signature_id": "f3a9c2e1-..."Enrichment requirements
When enrichment_enabled is true, every lead must include at least one
research signal: company, linkedin_url, or company_website. A company
value also lets the system extract the email domain and cross-reference it against
the company name before researching. A lead with none of these returns a 400
(enrichment would have nothing to work with).
Example request
curl -X POST "https://app.machfive.io/api/v1/campaigns/CAMPAIGN_ID/generate-batch" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"leads": [
{ "name": "Jane Doe", "title": "VP Marketing", "company": "Acme Inc", "email": "jane@acme.com" },
{ "name": "John Smith", "title": "CTO", "company": "Beta Co", "email": "john@beta.co" }
],
"options": {
"email_count": 3,
"email_signature": "Sam Rivera\nMachFive | Founder\n500 Market St, San Francisco, CA 94105",
"list_name": "API Batch Q1",
"enrichment_enabled": true,
"notification_email": "ops@yourcompany.com",
"additional_details": "Lead with the deliverability angle; keep it under 90 words."
}
}'Response (202 Accepted)
The request returns immediately. Processing continues in the background.
{
"list_id": "uuid-of-email_sequences-row",
"status": "processing",
"leads_count": 2,
"message": "Batch accepted. Processing will continue in the background. Poll list status or open in the UI."
}The response may also include sequence_id (deprecated); use list_id only.
| Field | Type | Description |
|---|---|---|
list_id | string (UUID) | Use this to poll GET /api/v1/lists/:list_id and to export with GET /api/v1/lists/:list_id/export. |
status | string | "processing". |
leads_count | number | Number of leads accepted for processing. |
message | string | Human-readable confirmation. |
Next steps
- Poll
GET /api/v1/lists/:list_iduntilprocessing_statusiscompletedorfailed. - When
completed, call GET/api/v1/lists/:list_id/export?format=csvor?format=jsonto download results.
See Lists for list status and Export for download details.
Error responses
| Status | Error | Description |
|---|---|---|
| 400 | BAD_REQUEST | Invalid JSON; missing leads; a lead missing/invalid email; email_count missing or not 1–4; no signature (neither email_signature nor signature_id) or both provided; an invalid options.notification_email; enrichment_enabled with a lead missing all of company/linkedin_url/company_website; or campaign setup is incomplete (no knowledge base yet and value propositions not completed). |
| 401 | UNAUTHORIZED | Missing or invalid API key. |
| 402 | INSUFFICIENT_CREDITS | Not enough credits for this many leads (1 per lead, or 2 with enrichment enabled). detail includes { required, available, payg_enabled, pct_of_cap }. |
| 403 | FORBIDDEN | Campaign not in this workspace. |
| 404 | NOT_FOUND | Campaign not found, or signature_id not found in this workspace. |
| 429 | RATE_LIMITED | Per-key rate limit exceeded; honor Retry-After. |
| 429 | WORKSPACE_LIMIT | Too many concurrent batch jobs; try again later. |
| 500 | INTERNAL_ERROR | Failed to enqueue or create list. |
Error body: { "error": "CODE", "message": "...", "detail"?: ..., "request_id": "..." }.
Note: This endpoint does not support
Idempotency-Key. A retried request enqueues a new batch. Credits are deducted on-success per completed lead. See Conventions → Idempotency for the endpoints that do.