1. Ask which events exist
GET /api/v1/webhooks/events returns a JSON array of event keys, for example proposal.accepted and eform.submitted. Subscribe only to keys in that list. The list is the contract. Do not hard-code a key you have not seen there.
proposal.accepted does not fire when you send the proposal. eform.submitted does not fire when you send the form.
2. Subscribe once per event
POST /api/v1/webhooks needs write access. One row is one event. To receive both events at the same URL, create two subscriptions.
hookUrl is your HTTPS endpoint. targetUrl is accepted as an alias for Zapier-style callers. Send one of them.
webhookSecret is optional. Omit it and OnboardMe generates one. The 201 returns id and webhookSecret once. Store the secret in your own vault before you respond 200 to your user. A later list of subscriptions does not show it again. If you lose it, unsubscribe and subscribe again.
3. Verify every delivery
OnboardMe POSTs JSON tohookUrl and sets:
The signature is HMAC-SHA256 of the string:
rawBody is the exact bytes you received, before JSON parsing and before any framework re-serialises the object. A parsed-and-reprinted body will not match.
4. Dedupe, then do the work
StoreX-Om-Event-Id. If you have already processed that id, return 200 and stop. OnboardMe retries when your endpoint is slow or returns an error, and a retry is the same event id with the same body.
Return 2xx quickly. Download PDFs, create bills, or call back into the API after you have persisted the event id, or from a queue. Doing that work inside the request is how you time out and get a second delivery.
The JSON body is the delivery for that event. Camel-case fields match the REST API.
proposal.accepted (schemaVersion 4):
eform.submitted (schemaVersion 1):
Do not treat either body as a full proposal or a full form definition. Load the REST resource when you need line items, files, or status that the event does not include.
5. Prove the endpoint, then remove it
POST /api/v1/webhooks/{id}/test sends a signed test delivery to that subscription. Verify your HMAC code against the test before you go live. The test is not a real proposal.accepted.
DELETE /api/v1/webhooks/{id} removes the subscription. Use the id from the 201, not the event name.
Production checklist
- HTTPS only, and a URL you control. A request-bin left over from development will receive client names.
- One secret per subscription, stored outside source control.
- Signature checked before you parse the body for business logic.
X-Om-Event-Idunique index so retries are harmless.- Handlers for the events you subscribed to, and a default that records and ignores anything else so a new event key cannot crash the endpoint.
Webhook reference
Events, subscribe, unsubscribe, and the test delivery.