Payment Links & Subscriptions

Create hosted payment links for one-time charges and direct billing installment plans, or standalone subscriptions for recurring monthly charges.

Base URL: https://payments.audit1.com/api/v1 — every endpoint on this page lives there. 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) — that host does not serve payment endpoints, and calling it for /payment-links returns 404.


POST /api/v1/payment-links
Field Type Required Description
employer_id string Yes Employer ObjectId
carrier_id string Conditional Carrier ObjectId. Required unless your API key is scoped to exactly one carrier — single-carrier keys infer it server-side
policy_id string Yes Policy ObjectId
premium_cents integer Yes Premium amount in cents ($1,500.00 = 150000)
fee_cents integer No Fee amount in cents (default: 0). Total charged = premium_cents + fee_cents
fee_breakdown array No Itemized fee labels: [{ "label": "Setup fee", "amount_cents": 5000 }]
payment_type string Yes ONE_TIME or DIRECT_BILLING
payment_context string Yes Purpose of the payment (see table below)
customer.name string Yes Insured business name
customer.email string Yes Email to receive the payment link
customer.phone string No Phone number
delivery.email boolean No Send link via email (default: true)
delivery.sms boolean No Send link via SMS (default: false)
total_installments integer Conditional Number of recurring installments. Required if payment_type is DIRECT_BILLING (min: 2)
down_payment_months integer Conditional Months of premium for down payment. Required if payment_type is DIRECT_BILLING (min: 1)
created_by string No User or system that created the link
after_completion_url string No URL to redirect after payment (must be a valid URL)
invoice_id string No Associate with an existing invoice
metadata object No Custom key-value pairs, string values only (e.g. { "invoice_number": "INV-2044" }). Stored on the link and its payment record, and returned in the payment.completed webhook's metadata field — this is the standard way to round-trip your own reference data through a payment. Your keys come back with their values untouched, but the object is not identical to the one you sent: we add api_client_id (your tenant id) and source: "payment_api" before storing it. Those two names are reserved — set either yourself and ours overwrites it, silently, so pick different names for your own data. Read the keys you set and ignore the rest; don't compare the whole object for equality

Fees

Audit1 charges no platform fee on payment links — there is no Audit1 rate to publish. Any amount on top of premium_cents is entirely yours to set via fee_cents; Audit1 never adds to it or takes a cut of it. The customer is charged the two together as one amount: total_cents = premium_cents + fee_cents.

When fee_cents is greater than 0, Audit1 records it and flags it as fee_source: "partner" — on the link, on the payment record, and in the payment.completed webhook — so it's always traceable back to you rather than to Audit1. Use fee_breakdown to itemize what the fee is for; it's stored for your own records but doesn't change how the charge or the webhook fields work.

Payment Context Values

Context Description
down_payment Initial down payment on a policy
installment Recurring installment payment
late_payment Late premium payment
extra_payment Additional payment beyond scheduled
paygo Pay-as-you-go premium collection
overdue_payment Overdue balance
premium_due Standard premium due
one_time_payment Generic one-time charge
full_payment Pay-in-full annual premium (single ONE_TIME charge)
deposit Deposit / hold
setup_fee Account setup fee
minimum_payment Minimum payment due
additional_payment Additional voluntary payment
audit1_fee Audit1 platform fee
extra_fee Extra fee
extra_carrier_fee Carrier-specific extra fee
bank_fee Bank-related fee
audit_program_fee Audit program fee
program_fee General program fee
remittance Remittance payment
late_registration_fee Late registration penalty
late_initial_reporting_fee Late initial reporting penalty
late_payroll_reporting Late payroll reporting penalty
late_quarterly_941s Late quarterly 941s penalty
late_state_unemployment Late state unemployment penalty
late_coi_reporting Late COI reporting penalty
payroll_billing_fee Payroll billing fee
manual_reporting_fee Manual reporting fee

Example: One-Time Payment

curl -X POST https://payments.audit1.com/api/v1/payment-links \
  -H "X-Client-ID: $CLIENT_ID" \
  -H "X-Client-Secret: $CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "employer_id": "681xyz789abc123456789012",
    "carrier_id": "680abc456def789012345678",
    "policy_id": "682def789ghi012345678901",
    "premium_cents": 250000,
    "fee_cents": 5000,
    "payment_type": "ONE_TIME",
    "payment_context": "down_payment",
    "customer": {
      "name": "Smith Industries",
      "email": "ap@smithindustries.com"
    }
  }'

carrier_id may be omitted here — single-carrier keys infer it server-side.

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": 255000,
    "link_amount_cents": 255000,
    "installment_plan": null
  }
}

Example: Direct Billing with Installment Plan

curl -X POST https://payments.audit1.com/api/v1/payment-links \
  -H "X-Client-ID: $CLIENT_ID" \
  -H "X-Client-Secret: $CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "employer_id": "681xyz789abc123456789012",
    "carrier_id": "680abc456def789012345678",
    "policy_id": "682def789ghi012345678901",
    "premium_cents": 1200000,
    "fee_cents": 50000,
    "payment_type": "DIRECT_BILLING",
    "payment_context": "down_payment",
    "total_installments": 10,
    "down_payment_months": 3,
    "customer": {
      "name": "Smith Industries",
      "email": "ap@smithindustries.com"
    }
  }'

carrier_id may be omitted here — single-carrier keys infer it server-side.

This creates a payment link for the calculated down payment portion. After the insured pays, a monthly subscription is automatically created for the remaining installments.

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": 1250000,
    "link_amount_cents": 312500,
    "installment_plan": {
      "total_installments": 10,
      "down_payment_percentage": 25,
      "down_payment_cents": 312500,
      "per_installment_cents": 93750,
      "extra_fee_cents": 0
    }
  }
}

In sandbox

, stripe_url won't be a checkout.stripe.com link — it points to an Audit1-hosted stub page (https://portal.audit1.com/pay/{id}) instead, since sandbox links never touch real Stripe. Use Simulate a Completed Payment below to mark it paid.

GET /api/v1/payment-links?carrier_id=...&employer_id=...&status=created&page=1&limit=50
GET /api/v1/payment-links/{id}
DELETE /api/v1/payment-links/{id}

Deactivates the link on Stripe and marks it as cancelled in the database. Cannot cancel a link that has already been paid (use refund instead).

Refund a Payment #

POST /api/v1/payment-links/{id}/refund
Field Type Required Description
amount_cents integer No Partial refund amount in cents (omit for full refund)
reason string No duplicate, fraudulent, or requested_by_customer

Refunds are tracked as refunded_cents on the payment record, with individual refund entries in a refunds array. Multiple partial refunds are supported.


Simulate a Completed Payment (Sandbox) #

POST /api/v1/payment-links/{id}/simulate-completion

The fastest way to test your integration end to end: mark a sandbox payment link as paid without a real card and without waiting for anyone to click through checkout. This is not a mocked copy of an event — it drives the exact same completion path a real Stripe payment does, and fires the exact same, correctly-signed payment.completed webhook to your registered endpoints.

Sandbox keys only. Call it with a live key and you get 403 Forbidden ("Completion simulation is available for sandbox keys only"). Only links created with a sandbox key exist to be simulated in the first place, so this can never touch real money.

It takes no parameters. Send an empty body — the endpoint always simulates the link's full total_cents being paid.

There is no short-payment option today.

An earlier version of this page documented an amount_cents body for simulating a partial payment. It does not work: this endpoint forwards no request body to the service that would honour it, so amount_cents is discarded in transit and you get a full-amount completion regardless. It has never behaved otherwise. If you need to exercise a partial-outstanding-balance branch, tell us at support@audit1.com — the capability exists one layer down and only needs plumbing through.

curl -X POST https://payments.audit1.com/api/v1/payment-links/683abc123def456789012345/simulate-completion \
  -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 '{}'

Response

{
  "ok": true,
  "data": {
    "_id": "683abc123def456789012345",
    "status": "paid"
  }
}

Calling it again on a link that's already paid is a safe no-op — you get the same response back (with already_paid: true added) instead of an error or a second webhook delivery.

Info

Today this only simulates pay-in-full (ONE_TIME) links. DIRECT_BILLING installment links aren't supported by this endpoint yet.

Register a webhook endpoint before you simulate a completion, or there's nothing listening for the event — see Payment Webhooks.


Subscriptions #

Standalone subscriptions for recurring monthly charges. Requires the employer to already have a Stripe customer (created automatically when a payment link is first created for that employer).

Create a Subscription #

POST /api/v1/subscriptions
Field Type Required Description
employer_id string Yes Employer ObjectId
carrier_id string Conditional Carrier ObjectId. Required unless your API key is scoped to exactly one carrier — single-carrier keys infer it server-side
policy_id string Yes Policy ObjectId
amount_cents integer Yes Amount per billing period in cents
payment_method_id string Yes Stripe payment method ID (e.g., pm_1abc...). The employer must have a Stripe customer first
metadata object No Custom key-value pairs

The billing interval is always month (monthly). The payment_method_id is set as the default payment method on the Stripe customer.

List Subscriptions #

GET /api/v1/subscriptions?carrier_id=...&status=active&page=1&limit=50

Get a Subscription #

GET /api/v1/subscriptions/{id}

Cancel a Subscription #

DELETE /api/v1/subscriptions/{id}

Cancels the subscription on Stripe and marks all remaining scheduled payments as cancelled.


Status Description
created Payment link created, awaiting payment
sent Link sent to customer (via email/SMS)
paid Payment received successfully
cancelled Manually cancelled
expired Link expired without payment

Refunds do not change the payment link status. Refund amounts are tracked separately via refunded_cents on the associated payment record.

Subscription Statuses #

Status Description
active Billing on schedule
past_due Payment failed, retrying
canceled Manually canceled
incomplete Initial payment failed or pending

Installment Plan Fields #

When payment_type is DIRECT_BILLING, the response includes an installment_plan object:

Field Type Description
total_installments integer Number of recurring installments
down_payment_percentage number Percentage of total used as down payment
down_payment_cents integer Calculated down payment amount in cents
per_installment_cents integer Amount per installment in cents
extra_fee_cents integer Additional fee applied to installments

The link_amount_cents in the response is the down payment amount (what the initial link charges). The remaining balance is collected via the auto-created subscription.


All monetary values are in cents. $1,500.00 = 150000. This avoids floating-point precision issues.