webhooks:inbound, both rate-limited to 60 requests / minute / org.
The org is always taken from the API key, never from the request body — an
org_id in the body is ignored.
Both endpoints tolerate HubSpot/Zapier field shapes: most fields can be sent flat or nested under a
properties object.Report a won deal
POST /api/v1/conversions attributes revenue. Mailr resolves the deal’s address to a mailed campaign and upserts
an idempotent conversion; the address is also recorded as an existing customer regardless of whether revenue
attributes. Unmatched deals are discarded.
200 OK — matched
200 OK — unmatched
string
required
The deal’s service address. Also accepted as
properties.address / deal_address / install_address.string
Your deal id. Drives idempotency. Also
properties.hs_object_id / objectId.string | number
Deal value. A number or numeric string.
string (ISO-8601)
Close date. Drives last-touch attribution within the 180-day window.
string
Optional Mailr campaign id for an exact, address-independent attribution.
string
Optional deal/contact details, stored with the conversion.
Sync a new lead (indirect)
POST /api/v1/tracking/lead records a lead your CRM captured elsewhere as an indirect lead against the mailed
campaign (source = crm_sync). Unmatched leads are discarded. Idempotency uses crm_record_id first, then a
non-empty email or phone. Records with none of those identity fields stay distinct instead of sharing an empty
email key. When a CRM record originated from Mailr, echo its mailr_lead_id; Mailr returns
{ "matched": false, "reason": "loop_guard" } without re-ingesting it. These leads are never delivered back outbound. If the
address already has a direct landing-page lead, the sync collapses onto it and returns duplicate: true with
attribution_type: "direct" — the existing lead is not downgraded.
200 OK — matched
200 OK — unmatched
Trigger a specific automation directly
POST /api/v1/webhooks/trigger?id=<automationId> fires one named automation — the older mechanism the Zapier app and
HubSpot workflows use. It’s still supported, but for new integrations prefer
POST /api/v1/events: it binds by event type instead of hardcoding an automation id, and
reports per-automation outcomes. Field extraction is highly tolerant of CRM/Zapier mappings; it’s idempotent on
deal_id (a repeat short-circuits before geocoding), and a deal_won automation also attributes revenue as a
side effect.
202 Accepted
GET /api/v1/automation/list → { "automations": [{ id, name, enabled }] }.
Registering existing customers
POST /api/v1/customers/webhook suppresses addresses from future mailings. Send a single { address, notes? } or
a batch { addresses: [...] }; it upserts on the normalized address per org and returns { added, total }. A
batch is capped at 1000 addresses — more is a 422. The endpoint is rate-limited to 60 requests / minute /
org in its own bucket (separate from the two attribution endpoints above); over-limit responses are 429 with
Retry-After: 60.