Payment API Overview

The Audit1 Payment API lets you collect insurance premiums from insured employers through multiple payment channels -- all from a single set of API credentials.

Who is this for?

Partners, carriers, and platforms (like billing systems) that want to programmatically collect premiums, down payments, and installments on behalf of their insureds.


Payment Methods #

Method How It Works Best For
Payment Sessions Send a link served on your own web address, with your logo and colour. Delivered by email or text for you. Invoicing an insured under your own brand
Payment Links Generate a secure Stripe checkout URL. Send to the insured via email. Down payments, late payments, one-time charges
Subscriptions Auto-charge on a recurring monthly schedule via Stripe. Monthly installments
Direct Debits Pull funds directly from a linked bank account via ACH. PayGo collections, recurring premiums
Bank Linking Embed Plaid bank account verification in your UI. Connecting insured bank accounts securely

How It Works #

1. Authenticate with your API key (must have "payments" or "all" scope)
2. Create a payment (link, subscription, or direct debit)
3. Insured pays (clicks link, or bank debited automatically)
4. Receive webhook notification when payment completes
5. View commissions earned

Flow #

flowchart LR platform["Your Platform"] api["Audit1 Payment API
Scoped API key"] links["Payment Links
Stripe checkout"] subs["Subscriptions
Stripe recurring"] debits["Direct Debits
ACH transfers"] bank["Bank Linking
Plaid verification"] platform --> api api --> links api --> subs api --> debits api --> bank classDef primary fill:#4f39f6,color:#ffffff,stroke:#4f39f6,stroke-width:2px; class api primary

Base URL #

https://payments.audit1.com/api/v1

This is a different host from the core Developer API (https://apiv2.audit1.com/api/v2, used for payroll reports, employee sync, and API keys). None of the endpoints documented on this page or the following pages exist on that host: /payment-links, /ach, /bank-accounts and /intake all return 404 there. If an endpoint documented here looks "missing," check that you're calling payments.audit1.com, not apiv2.audit1.com.

Warning

/webhooks is the exception, and it will mislead you. The Developer API host has its own, unrelated /webhooks route reserved for internal administration, so calling it on apiv2.audit1.com returns 401 Unauthorized, not 404. That is not a verdict on your credentials — it means you are on the wrong host. Do not use a 404 as your "wrong host" signal for this one path; check the hostname instead. The webhook endpoints you want are the ones on payments.audit1.com documented in Payment Webhooks.

Both sandbox and production use the same URL. Your API key prefix determines the environment: - audit1_test_cli_* / audit1_test_sec_* = sandbox - audit1_live_cli_* / audit1_live_sec_* = production


Authentication #

Send your Client ID and Client Secret as headers with every request.

X-Client-ID: audit1_test_cli_a1b2c3d4...
X-Client-Secret: audit1_test_sec_f6e5d4c3...
Content-Type: application/json

Your API key must have payment scope (scope: "payments" or scope: "all"). The auth middleware explicitly filters for these scopes -- keys with only payroll scope are rejected with 401 Unauthorized.

Scope Enforcement #

API keys are validated in two layers:

  1. Auth middleware -- Verifies client_id + client_secret (bcrypt), checks the key has payments or all scope, and validates environment prefix matches key record.
  2. Tenant scope middleware -- Loads the Payment_api_clients record for the authenticated owner. This record defines allowed_carrier_ids and allowed_employer_ids. Requests for entities outside your scope return 403 Forbidden. Empty arrays = access to all (typically for platform-level integrations).

Optional HMAC Signature #

For additional security, include an HMAC-SHA256 signature with each request:

X-Signature: <hmac_sha256_hex>
X-Timestamp: <epoch_milliseconds>

Signature payload: ${timestamp}.${method}.${path}.${body}

Requests with timestamps older than 5 minutes are rejected (replay protection).

See Authentication for full details on key management, environments, and HMAC signing.


Response Format #

All responses use a consistent envelope:

{
  "ok": true,
  "data": { ... },
  "pagination": {
    "page": 1,
    "limit": 50,
    "total": 123,
    "total_pages": 3
  }
}

Errors:

{
  "ok": false,
  "error": "Bad Request",
  "message": "Required fields: employer_id, carrier_id, policy_id"
}

Rate Limiting #

Default
Limit 100 requests/minute per API key
Headers X-RateLimit-Limit, X-RateLimit-Remaining, Retry-After
Exceeded 429 Too Many Requests with Retry-After seconds

Custom rate limits can be configured per partner via the Payment_api_clients.rate_limit field.


curl -X POST https://payments.audit1.com/api/v1/payment-links \
  -H "X-Client-ID: audit1_test_cli_your_id_here" \
  -H "X-Client-Secret: audit1_test_sec_your_secret_here" \
  -H "Content-Type: application/json" \
  -d '{
    "employer_id": "681xyz789abc123456789012",
    "carrier_id": "680abc456def789012345678",
    "policy_id": "682def789ghi012345678901",
    "premium_cents": 145000,
    "fee_cents": 5000,
    "payment_type": "ONE_TIME",
    "payment_context": "down_payment",
    "customer": {
      "name": "ACME Corp",
      "email": "billing@acme.com"
    }
  }'

Response (201 Created)

{
  "ok": true,
  "data": {
    "_id": "683abc123def456789012345",
    "stripe_payment_link_id": "plink_1abc2def3ghi...",
    "stripe_url": "https://checkout.stripe.com/c/pay/cs_a1b2c3...",
    "status": "created",
    "billing_entity_type": "employer",
    "total_cents": 150000,
    "link_amount_cents": 150000,
    "installment_plan": null
  }
}

Send the stripe_url to your insured. When they pay, you receive a payment.completed webhook.

Testing in sandbox?

You don't have to wait for a real payment — see Simulate a Completed Payment to mark a sandbox link as paid and fire that webhook yourself.


Webhook Events #

The following events are dispatched to registered webhook endpoints:

Event Description
payment.completed A payment taken through Stripe checkout completed — a card, or a Stripe bank debit where that method is offered. It never fires for Audit1's own bank rail
payment.failed Payment attempt failed
payment.refunded Payment refunded (full or partial)
subscription.created New subscription activated
subscription.cancelled Subscription cancelled
installment.paid Installment payment received
installment.failed Installment payment failed
payment.debit_minted A scheduled ACH debit was created and can still be cancelled
payment.debit_cancelled A scheduled ACH debit was cancelled before it moved money
payment.debit_cleared A bank debit was matched in the bank account that received it — the money is actually there. Only carriers whose collected money lands in an Audit1 collection account can produce it, because nowhere else is there an account we can read
payment.debit_settled The ACH processor reports a bank debit settled. The processor's word, not a bank match. Sent today only for carriers that settle into their own bank, where no account we can read is ever involved — so the processor's report is the strongest confirmation that can exist there

A bank payment made on a payment session reports through the two payment.debit_* events above, not through payment.completed — subscribing to payment.completed alone means never hearing about one. Which of the two you get follows the carrier's settlement rail, and some carriers produce neither. Subscribe to both names and handle whichever arrives; Payment Webhooks has the payloads, the rails, and the delivery contract.


Next Steps #

Guide What you'll learn
1 Payment Sessions Send a branded invitation to pay on your own domain
2 Payment Links & Subscriptions Create, list, cancel, and refund payments
3 Direct Debits Initiate automated bank debits and batch collections
4 Bank Accounts & Linking Link bank accounts and manage debit credentials
5 Payment Webhooks Receive real-time payment event notifications