Events
POST /attribution/events
Records a conversion event. The authoritative source for revenue + funnel state changes — emit from your server (or a CRM webhook), not the browser.
Auth: Admin API key OR scoped key with events:write.
Request
POST <base>/attribution/eventsAuthorization: Bearer <key>Content-Type: application/json
{ "userId": "user_abc", "type": "invoice_paid", "value": 49.00, "currency": "USD", "metadata": { "stripe_invoice_id": "in_12345" }, "ts": "2026-04-24T12:00:00Z"}| Field | Type | Required | Notes |
|---|---|---|---|
userId | string | yes | Same identifier you assigned at signup time so OpenPartner can stitch the event to a click. |
type | string | yes | Standard or custom event name. Conventions: signup, trial_started, subscription_created, invoice_paid, opportunity_won, trial_converted. |
value | number | conditional | Required for events that drive percent commissions. Decimal in major units (dollars, not cents). |
currency | string | conditional | ISO 4217. Defaults to USD when value is set. |
metadata | object | no | Free-form. Stored on the Event row; surfaced in attribution + webhook payloads. |
ts | string | no | ISO 8601 timestamp. Defaults to server time. Set this when forwarding async events to preserve attribution-window math. |
Response
{ "ok": true, "eventId": "01HXX...", "attribution": { "status": "attributed", "model": "last_click", "touches": [ { "clickId": "01HXX...", "partnerId": "01HXX...", "weight": 1, "attributionId": "01HXX...", "commissionId": "01HXX..." } ] }}attribution.status is one of:
attributed— at least one click stitched to this user’s identity, attribution + commission rows writtenno_clicks— no clicks tied to this user; event recorded but unattributedalready_attributed— duplicate event (sameuserId+type+ closets)
Common patterns
HubSpot Workflows / Zapier / Make: wire your CRM’s “deal stage = closed_won” trigger to
POST here with type: 'opportunity_won'. See CRM integration for
the full setup walkthrough.
Stripe webhooks: if your billing system is Stripe, subscribe to invoice.paid and POST
here with type: 'invoice_paid' + the customer’s userId. Or use the OpenPartner SDK to
emit directly from your server-side checkout handler.
Idempotency
Pass Idempotency-Key: <unique> to make event creation safe to retry. The same key returns
the original event without creating a duplicate. Useful when re-firing CRM webhooks.