Inbound Sources
Push data from Stripe, Typeform, or any webhook into Coeffection without handing out an API key. Each source is a signed, per-tenant endpoint that can only stage events โ your own workflows decide what becomes a Contact, a Lead, or anything else.
How it works#
An external system signs a payload and POSTs it to your source's endpoint. Coeffection verifies the signature and writes the raw event to a staging table โ it never creates CRM records directly. A workflow you author (triggered by External event) then maps the staged payload onto entities. You choose whether that happens instantly (Auto) or after a human reviews it (Review).
Create a source#
Go to Admin โ Integrations โ Inbound Sources โ New.
Name & mode
Target workflow
External event appear here โ if you have none yet, the dropdown links you to create one.Dedupe key
id). Replays of the same id are ignored, so a retrying sender never double-creates records.Copy the signing secret
Admin โ Integrations โ Inbound Sources
Describe the payload shape#
On the source's Payload Shape tab, paste a sample event and click Detect fields. Coeffection walks the JSON (including nested objects via dot-paths like customer.email) and lets you mark which fields show in the Review inbox and which is the dedupe key. The full raw payload is always stored โ this just drives the inbox columns and the $event.* references your workflow can use.
Sign your requests#
Every request is authenticated with an HMAC-SHA256 signature over <timestamp>.<raw body>, sent in an x-webhook-signature header as t=<unix_seconds>,v1=<hex>. The timestamp must be within ยฑ5 minutes (replays are rejected). The source editor gives you a copy-paste snippet; here are the essentials:
import crypto from "node:crypto";
const SECRET = process.env.COEFFECTION_SIGNING_SECRET; // shown once on create
const ENDPOINT =
"https://app.coeffection.com/api/ingest/<tenantId>/<sourceSlug>";
const body = JSON.stringify({ id: "evt_123", email: "ada@acme.com" });
const t = Math.floor(Date.now() / 1000); // unix seconds
const v1 = crypto
.createHmac("sha256", SECRET)
.update(`${t}.${body}`) // sign "<timestamp>.<raw body>"
.digest("hex");
await fetch(ENDPOINT, {
method: "POST",
headers: {
"content-type": "application/json",
"x-webhook-signature": `t=${t},v1=${v1}`,
},
body,
});import hashlib, hmac, json, time, requests
SECRET = "..." # shown once on create
ENDPOINT = "https://app.coeffection.com/api/ingest/<tenantId>/<sourceSlug>"
body = json.dumps({"id": "evt_123", "email": "ada@acme.com"})
t = int(time.time())
v1 = hmac.new(SECRET.encode(), f"{t}.{body}".encode(), hashlib.sha256).hexdigest()
requests.post(
ENDPOINT,
headers={"content-type": "application/json", "x-webhook-signature": f"t={t},v1={v1}"},
data=body,
)Sign the exact bytesyou send โ don't re-serialize the JSON, since key order and spacing change the signature.
Map events with a workflow#
In the workflow builder, choose the External event trigger and pick this source. Then add Create entity actions that read payload values with $event.<path>. To link records, give a node a Store as name and reference its id downstream with $<name>.id.
Example: a purchase becomes a Contact + Lead
$company.id.Auto vs. Review#
The workflow runs the instant a signed event arrives. Best for trusted, high-volume sources like completed purchases.
Events wait in the Inbound Inbox with your chosen columns. A teammate clicks Promote to run the workflow or Reject to discard. Best for demo requests, form fills, or anything needing a glance first.
Security & safeguards#
- Staging-only by construction. The ingress endpoint physically cannot write CRM records โ only your workflow can, under your rules.
- System fields are off-limits. A payload can never set ownership or identity columns (tenant, owner, account, status, record id) โ those are managed by Coeffection.
- Tenant-scoped.The endpoint carries your tenant in the URL; a payload can't reassign an event to another tenant.
- Per-event cap.One event can only create a bounded number of records, so a replay storm can't exhaust your data.
- Revocable. Rotate a secret or deactivate a source at any time; in-flight requests with the old secret stop working immediately.
401โ there's no way to probe which tenants or sources exist.