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 #

  1. Go to Settings > Connections > Set Up Connection > Webhooks
  2. The wizard generates a webhook URL and signing secret
  3. 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.