Help
Changelog
Client API version history.
Version numbers match info.version on this API.
Breaking changes increment the major version. Additive endpoints and fields increment minor. Patch is reserved for documentation-only or non-contract fixes.
1.15.0
CRM-ready webhook identity on every lead email event
Added
- Shared lead identity block on
email.sent,reply.received,reply.categorized, andbounce.detected:email,mailbox_email,campaign_name, contact fields, and nestedcustom_fields email.sentbody_text(plain text, 16,000 character cap) plusstep_number/node_id/flow_node_idwhen knownbounce.detectedexplicitemailandreason(severity+ SMTPcode)- Block list group:
blocklist.entry_addedandblocklist.entry_removedfor everyblock_listinsert or delete (inbox, API, reply opt-out, import, bounce suppression). Email rows may include the lead identity block. Domain rows send the host only (example.com) with noemailor identity fields. A hard bounce may emit bothbounce.detectedandblocklist.entry_added custom_fields_truncated: truewhen custom fields exceed the 8 KB byte budget
Changed
- Existing event keys are unchanged. Empty contact fields are omitted rather than sent as empty strings.
1.14.0
Campaign start and pause dates
Added
lifecycle_scheduleon campaign create/update/detail:time_zone, nullablestart_on/pause_oncalendar dates, and read-only derivedstart_at/pause_at- Campaign status
scheduledfor launches with a futurestart_on - Launch returns
runningorscheduledplus the savedlifecycle_schedule
Changed
- Empty
start_onstill launches immediately. Emptypause_onnever auto-pauses.pause_onis exclusive: sending stops before that local day.
1.13.0
Webhook identity fields for CRM sync
Added
email.sentdatanow includesemail(lead recipient),mailbox_email, andcampaign_nameso CRM integrations can match contacts without a Furnace API keyreply.receiveddatanow includesbody_text(plain-text display body, quoted thread stripped, truncated at 16,000 characters), plusmailbox_emailandcampaign_name
Changed
- Existing
email.sent/reply.receivedkeys are unchanged. Omitted new fields are not sent as empty strings;campaign_namemay benullif the campaign row has no name.
1.12.0
Lead tags and email verification on import
Added
- Optional
tags(array of names/aliases) andemail_verificationonLeadCreate— create, bulk, async, and staged import all inherit the same fields - Person-level lead tags (catalog + account-owned) resolved by name; unknown names find-or-create an account tag
- Structured verification facts (
ok/catch_all/invalid/unknown/disposable) stored separately from tags
Changed
- Omitting the new fields behaves exactly as 1.11.0.
additionalProperties: falsestill rejects unknown keys such asmv_result.
1.11.0
Bulk-first MCP / Client API
Added
GET /v1/meta/limits— page sizes, sync/async caps, queued vs running job quotas, supported scopes/operations, file-ingress capabilitiesPOST /v1/bulk/preview— estimate matched/excluded/actionable counts; bind execution withpreview_id- Staged lead import:
POST /v1/campaigns/{id}/imports/staged,POST /v1/jobs/{id}/staging-rows,POST /v1/jobs/{id}/finalize - Optional
POST /v1/uploads/presignfor direct S3 CSV upload (upload_id); local filesystem paths are never accepted POST /v1/people/export(exportPeople) and compact email/global_lead_idprojectionPOST /v1/campaigns/{id}/enroll(enrollPeople) with server-sidescope+exclusionsPOST /v1/lead-lists/{id}/members:bulk(updateLeadListMembership) async add/removePOST /v1/jobs/{id}/cancel— cancel queued/uploading immediately; stop running jobs between chunks- Job operations:
add_to_lead_list,remove_from_lead_list,export_leads,csv_lead_import_staged - Campaign detail now returns attached
mailbox_ids
Changed
- Async job capacity: only running jobs consume the concurrent slot (default 3); additional jobs stay queued up to a separate quota
createAsyncJobacceptsscope,exclusions,preview_id,target_list_id,source_campaign_id, and export projection fields- Lead-source
bucketIdis normalized to the campaign bucket on create/save; richText variants derivebody_htmlfromtemplate/body_textwhen empty
1.10.0
Campaign create defaults to Central business hours
Changed
POST /v1/campaignsnow defaults omittedscheduleto Central 9–5 Mon–Fri (America/Chicago). Pass"schedule": nullfor 24/7.- Omitted
sending_interval_secondsdefaults to1440(24 minutes; ~20 emails per mailbox per day on the default window), replacing the previous300default.
1.9.0
Replace lead preview + structured errors
Added
GET /v1/threads/{id}/replace-lead/preview?email=— read-only preview of create vs attach, block-list status, match count, and whether the write would be refused (allowed/disallowed_reason)- MCP tool
previewThreadLeadReplacement(auto-generated from the new endpoint) POST /v1/threads/{id}/replace-leadacceptsnew_mobile_phone_number- The same response returns
target_lead_id: the pre-existing contact onmode = attached, otherwisenull
Changed
- Replace-lead business-rule failures now return structured 400/403/404/409 instead of opaque 500s (
same_as_current_lead,lead_already_replaced,target_missing_enrollment,target_already_replaced,lead_not_found,invalid_reason, …) replaceThreadLeaddescription documents create vs attach side effects and points agents at the preview tool
1.8.0
Replace lead reuses an existing campaign contact
Added
POST /v1/threads/{id}/replace-leadreturnsmode:attachedwhen the replacement address was already a live lead in the campaign,createdotherwise- The same response returns
retired_sibling_count, how many duplicate rows of that address had their sequence stopped
Changed
- Replacing to an address that is already in the campaign no longer creates a second lead. The existing contact is reused, the conversation moves to them, and the replaced lead is retired as stopped/replaced instead of archived.
new_lead_idis that pre-existing contact. - The call now fails if the existing contact has no enrollment in the campaign, since the forward would have nothing to send against
1.7.0
Account settings + MCP surface
Added
GET/PUT /v1/webhooks— account webhook URL, signing secret, enabled eventsGET/POST /v1/api-keys,DELETE /v1/api-keys/{id}— create returns secret once; list omits secretPOST/GET /v1/mailboxes/connect-sessions— start mailbox connect handoff and poll status
1.6.1
People response shape + request body hygiene
Changed
GET /v1/peopleand lead-list people pages now return the same person fields as detail/PATCH, withlatest_activity_at(list no longer emitslatest_activityor per-rowtotal_count)PATCH /v1/campaigns/{id}accepts"schedule": nullto clear the send window (24/7)- Unknown keys on primary request bodies are ignored (stripped) so handlers match closed OpenAPI schemas
1.6.0
Inbox triage timestamps
Added
- Thread responses include
last_inbound_at— latest inbound lead reply timestamp
Changed
GET /v1/threadsdate_from/date_toand Newest/Oldest sort now uselast_inbound_at(lead reply time), notlast_message_atlast_message_atremains latest activity in either direction
1.5.0
Inbox thread search
Changed
GET /v1/threads?q=— free-text search now matches subject, participants, lead name/email/company, campaign name, thread tags, and message bodies (prefix/FTS; minimum 2 characters)
1.4.3
Self-hosted docs rebuild (Fumadocs + OpenAPI reference + agent layer)
Changed
- Replaced Starlight/Scalar with a unified Fumadocs site at
/docs - API reference at
/docs/reference/uses fumadocs-openapi inside the Furnace docs shell (read-only, no try-it console) - Documentation and API Reference are separated in the header (Mintlify-style tabs)
- Split building campaigns into quickstart, flow, launch, and flow-schemas guides
- Auto-generated
llms.txt,llms-full.txt, and per-page.mdmirrors for agent access
1.4.2
Starlight documentation site
Changed
- Replaced Scalar at
/docswith a Starlight static docs site (guides + OpenAPI reference via starlight-openapi) - Removed phantom
/documentation/*OpenAPI paths; guides export from TS builders at build time - Building campaigns guide now documents
POST /flowas the hero save (PUT remains a deprecated alias)
1.4.1
Documentation consolidation
Changed
- Removed the Campaign flow reference guide page — field-level flow object docs now live in Models (
CampaignFlow,FlowUpdate,FlowValidationIssue, and related node schemas) - Building campaigns guide and flow API endpoint descriptions now link to Models schemas
1.4.0
Campaign build lifecycle & flow pipeline
Added
- Building campaigns guide in
/docs(Guide → Building campaigns) with lifecycle rules, copy-pasteable flow JSON, and draft-vs-live locking behavior - Campaign flow reference guide (
/documentation/campaign-flow-reference) — field-by-field flow object reference, merge variables, normalization rules, and full validation error-code catalog POST /v1/campaigns— create a draft campaign with optional mailboxes, tags, schedule, and initial flowPOST /v1/campaigns/{id}/flow— hero flow save withflow_revision,field_sync, and optionalIf-MatchconcurrencyPOST /v1/campaigns/{id}/flow?dry_run=true— dry-run alias for flow validation without persistingPUT /v1/campaigns/{id}/flow— write the canonical campaign flow payload (deprecated alias ofPOST)POST /v1/campaigns/{id}/flow:validate— dry-run normalization, validation, and lifecycle gatingPATCH /v1/campaigns/{id}/status— pause, resume, or stop live campaigns (running|paused|stopped)PATCH /v1/campaigns/{id}/flow/nodes/{nodeId}— live content-only node patchGET /v1/flow-templates— starter flow graphsGET /v1/campaigns/{id}?include=launch_state,lead_field_state— checklist observability without extra validate callsPOST /v1/campaigns/{id}/launch— start a draft campaign after backfilling enrollmentsfield_syncon flow saves — auto-declares merge-variable fields from email copy
Changed
GET /v1/campaignslist responses omitflow_data; useGET /v1/campaigns/{id}for the full flow- Campaign detail responses include computed
flow_revision POST /v1/campaigns/{id}/launchreturns{ enrolled: N }and uses shared launch validation- Live campaign flows are now topology-locked in both the API and the builder UI. Structural edits return
403 permission_errorwith codeflow_locked. POST /v1/campaigns/{id}/lead-fieldsnow writes flow data through the same service-role-safe persistence path as the new flow endpoints.- Building campaigns guide expanded with end-to-end curl walkthrough,
flow:validateresponse examples, structural change reason codes, launch preconditions, and troubleshooting table - OpenAPI schemas for flow node types (
EmailVariant,LeadSourceNodeData,EmailNodeData,WaitTimeNodeData,AICategorizerNodeData,DataSenderNodeData,FlowNode,FlowEdge,FlowValidateResult) now include per-field descriptions and examples
1.3.0
Webhooks — categorization and delivery infrastructure
Added
- Outbound webhook
reply.categorizedwhen a thread reply category is assigned, changed, or cleared - Granular per-event webhook subscription in Account Settings (expand event groups to pick individual types)
Changed
- Campaign pause, resume, and stop from the Furnace app now emit
campaign.paused,campaign.resumed, andcampaign.stoppedwebhooks (previously Client API only) PATCH /v1/threads/{id}category updates emitreply.categorized
1.2.0
Inbox expansion — triage, outbound messaging, and ops endpoints for programmatic inbox use.
Added
- Webhooks guide in
/docs(Guide → Webhooks) with example payloads for every outbound event type - Consolidated
/docsinto a single Scalar document with Guide and API sidebar sections
Thread list & triage
GET /v1/threads— new query params:q,unread_only,conversation_status,category(no_categoryfor uncategorized),tag_ids,date_from,date_to,has_reply_only(defaulttrue)PATCH /v1/threads/{id}— partial update:category,conversation_status,read
Outbound messaging
POST /v1/threads/{id}/forward— queue forward job (forward_message_idrequired)GET /v1/message-jobs/{id}— poll reply/forward job statusPOST /v1/message-jobs/{id}/cancel— cancel queued/failed outbound jobPOST /v1/message-jobs/{id}/send-now— expedite queued outbound job
Inbox ops
PUT /v1/threads/{id}/out-of-office— set OOO (resume_mode:scheduled|instant|none)DELETE /v1/threads/{id}/out-of-office— clear OOOPOST /v1/threads/{id}/replace-lead— replace thread lead; optionalforward_message_idGET /v1/thread-tags— list account thread tagsPOST /v1/threads/{id}/tags:add/tags:remove— assign or remove tag on thread
Changed
POST /v1/threads/{id}/reply— optionalin_reply_to_message_id(defaults to latest message)
Notes
- Poll outbound sends with
/v1/message-jobs/{id}, not/v1/jobs/{id}(import jobs only). - Tag create/edit/delete remains in the Furnace app; the API supports list + assign/remove only.
1.1.0
People, lists, jobs, and batch webhooks
Added
GET/PATCH /v1/people,GET/PATCH /v1/people/{globalLeadId}GET/POST/PATCH/DELETE /v1/lead-lists, list membership endpointsPOST /v1/jobs,GET /v1/jobs/{id}— async bulk operations- Campaign/mailbox tag CRUD and filtering
- Sync bulk shortcuts:
leads:add,leads:remove,leads:remove-from-all-campaigns, enrollment pause/resume - Batch completion webhooks (
*.completed) for bulk and enrollment actions
Changed
- Webhook allowlist: removed
enrollment.created/enrollment.updated; added batch completion events
1.0.0
Initial Client API
Added
- Campaigns, leads, mailboxes, block list, campaign stats
- Basic inbox:
GET /v1/threads,GET /v1/threads/{id},GET /v1/threads/{id}/messages,POST /v1/threads/{id}/reply - Atomic webhooks:
lead.*, campaign lifecycle,email.sent,reply.received,bounce.detected - OpenAPI at
/openapi.json, Scalar UI at/docs