Webhooks
Audit1 supports inbound webhooks -- push payroll data to a connection-specific URL instead of calling the REST API.
Webhook connections are set up in your portal: Settings > Connections > Set Up Connection > Webhooks.
Inbound -- Push Data to Audit1 #
Push payroll data to a webhook URL instead of calling the REST API. Each URL is tied to a specific connection.
Setup #
- Go to Settings > Connections > Set Up Connection > Webhooks
- The wizard generates a webhook URL and signing secret
- Your URL:
https://webhooks.audit1.com/api/v1/webhook/inbound/{connection_id}
Request #
The body is the same format as POST /payroll/reports.
Required headers:
| Header | Value |
|---|---|
X-Webhook-Signature |
HMAC-SHA256(secret, "${timestamp}.${body}") hex digest |
X-Webhook-Timestamp |
Unix milliseconds (within 5 min of server time) |
Signature Computation #
signed_payload = "${timestamp}.${raw_request_body}"
signature = HMAC-SHA256(webhook_secret, signed_payload)
The signature is a raw hex string -- no
sha256=prefix.
Example #
TIMESTAMP=$(date +%s%N | cut -b1-13)
BODY='{"employer_fein":"12-3456789","policy_number":"WC1025561","employees":[{"first_name":"John","last_name":"Doe","class_code":"8810","state":"CA","gross_wages":5000.00,"hours_worked":80}],"pay_period":{"start_date":"2026-03-01","end_date":"2026-03-15"}}'
SECRET="your_webhook_secret"
SIGNATURE=$(echo -n "${TIMESTAMP}.${BODY}" | openssl dgst -sha256 -hmac "${SECRET}" | sed 's/^.* //')
curl -X POST "https://webhooks.audit1.com/api/v1/webhook/inbound/YOUR_CONNECTION_ID" \
-H "Content-Type: application/json" \
-H "X-Webhook-Signature: ${SIGNATURE}" \
-H "X-Webhook-Timestamp: ${TIMESTAMP}" \
-d "${BODY}"
Errors #
| Status | Error | Cause |
|---|---|---|
| 400 | Invalid connection_id | connection_id is not a valid ObjectId |
| 400 | Connection is not a webhook type | Connection exists but is not configured for webhooks |
| 400 | Missing or empty employees array | employees field missing, not an array, or empty |
| 401 | Missing required headers | X-Webhook-Signature or X-Webhook-Timestamp missing |
| 401 | Request timestamp expired | Timestamp > 5 minutes old |
| 401 | Invalid webhook signature | HMAC doesn't match |
| 403 | Webhook connection is inactive | Connection was disconnected or deleted |
| 404 | Webhook connection not found | Bad connection ID or connection was soft-deleted |
| 404 | Could not resolve employer | Neither connection's employer_id nor body's employer_fein matched an employer |
| 502 | File processing failed | Files-creator returned an error |
Outbound Webhooks — Not Yet Available #
Status: planned, not yet emitted.
Audit1 does not yet dispatch outbound webhooks. The CRUD endpoints below let you pre-register an endpoint and event list, but no events are currently delivered. Subscribe to the changelog for the launch date — once dispatching is live, every event will carry an X-Webhook-Signature header computed the same way as the inbound signing scheme described above.
For real-time data today, poll GET /files/status/:file_id after submitting payroll.
Webhook Management (portal-only) #
Webhook registrations are managed through internal portal APIs. These endpoints are not accessible via developer API keys -- they are internal to the Audit1 portal.
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/v1/webhooks |
Register webhook (portal only) |
| GET | /api/v1/webhooks |
List webhooks by owner (portal only) |
| PATCH | /api/v1/webhooks/:id |
Update webhook URL, events, or status (portal only) |
| DELETE | /api/v1/webhooks/:id |
Delete webhook (portal only) |
To manage webhooks, use Settings > Connections in your portal dashboard.
Testing Locally #
Use ngrok to expose your local server:
node webhook-server.js # running on localhost:8080
npx ngrok http 8080 # creates public HTTPS URL
Use the ngrok URL as the employer_fein fallback test target, or set up a connection that points to your ngrok URL.
Need help? Email support@audit1.com with your connection ID and the error you're seeing.