Payment Links & Subscriptions
Create hosted payment links for one-time charges and direct billing installment plans, or standalone subscriptions for recurring monthly charges.
Payment Links #
Create a Payment Link #
POST /api/v1/payment-links
| Field | Type | Required | Description |
|---|---|---|---|
employer_id |
string | Yes | Employer ObjectId |
carrier_id |
string | Yes | Carrier ObjectId |
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 (injected into Stripe metadata) |
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 |
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 /api/v1/payment-links \
-H "X-Client-ID: $CLIENT_ID" \
-H "X-Client-Secret: $CLIENT_SECRET" \
-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"
}
}'
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 /api/v1/payment-links \
-H "X-Client-ID: $CLIENT_ID" \
-H "X-Client-Secret: $CLIENT_SECRET" \
-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"
}
}'
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
}
}
}
List Payment Links #
GET /api/v1/payment-links?carrier_id=...&employer_id=...&status=created&page=1&limit=50
Get a Payment Link #
GET /api/v1/payment-links/{id}
Cancel a Payment Link #
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.
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 | Yes | Carrier ObjectId |
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.
Payment Link Statuses #
| 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_centson 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.