API reference SaaS
SaaS Endpoints
POST /saas/subscribe
Creates a new SaaS subscription for the company. Stores the card in the TalusPay vault for recurring billing and charges the first month.
If the company has an active free trial (today is strictly before the trial end date), the card is stored in the vault but no charge is made. The billing day is set to the day of the free trial end date, and the first charge will occur on that date via the daily billing cron. If the company subscribes on the trial end date (edge case), they are charged normally as if no trial existed.
Authentication: Bearer token (ADMIN only)
Request Body:
{
"maxEmployees": 3,
"token": "tok_abc123...",
"paymentType": "card"
}
| Field | Type | Required | Description |
|---|---|---|---|
| maxEmployees | number | Yes | Number of users for the subscription (minimum 1) |
| token | string | Yes | Payment token from TalusPay tokenizer |
| paymentType | string | No | card (default) or ach |
Response (201):
{
"message": "Subscription created successfully",
"subscriptionStatus": "ACTIVE",
"maxEmployees": 3,
"billingDayOfMonth": 15,
"amountCharged": 7500,
"transactionId": "txn_abc123"
}
Response when free trial is active (201):
{
"message": "Subscription created successfully (free trial active — no charge until trial ends)",
"subscriptionStatus": "ACTIVE",
"maxEmployees": 3,
"billingDayOfMonth": 1,
"amountCharged": 0,
"freeTrialEndDate": "2026-05-01"
}
Pricing: Base price of $45.00 (4500 cents) for the first user + $30.00 (3000 cents) for each additional user. Custom pricing may be configured per company. When the total is $0 (custom pricing) the card is vaulted, nothing is charged and transactionId is omitted.
Error Responses:
400- Missing or invalid fields, or a payment gateway error ("Payment error: ...")401- Unauthorized402- Payment declined (the vault record created for this attempt is removed)403- Not an admin employee409- Company already has an active subscription (checked before the body is validated)502- TalusPay could not create the vault customer or store the payment method
PATCH /saas/max-employees
Increases the maximum number of employees for the company. Charges for the additional users using the stored payment method.
Authentication: Bearer token (ADMIN only)
Request Body:
{
"maxEmployees": 5
}
| Field | Type | Required | Description |
|---|---|---|---|
| maxEmployees | number | Yes | New maximum employee count (must be greater than current) |
Response (200):
{
"message": "Max employees increased successfully",
"previousMax": 3,
"newMax": 5,
"additionalUsers": 2,
"amountCharged": 4000,
"transactionId": "txn_def456"
}
While the company's free trial is still active (today is strictly before the subscription's freeTrialEndDate), or when the computed charge is $0, nothing is charged: amountCharged still reports the computed amount and transactionId is omitted.
Error Responses:
400- New max not greater than current, no active subscription, missing or invalidmaxEmployees, or a payment gateway error ("Payment error: ...")401- Unauthorized402- Payment declined403- Not an admin employee
PUT /saas/payment-method
Updates the stored payment card for the company's SaaS subscription. Adds the new card to the TalusPay vault and removes the old one.
If the subscription status is PAYMENT_FAILED, the month whose charge was declined is still owed: the new payment method is charged immediately (same amount the billing run charges — billable employees x pricing) and the subscription returns to ACTIVE only if that charge is approved. On approval billingDayOfMonth is re-anchored to the day of this charge. If the charge is declined the endpoint returns 402, the new method is removed from the vault, and the subscription stays PAYMENT_FAILED with the previous method on file. An ACTIVE subscription is never charged by this endpoint.
Authentication: Bearer token (ADMIN only)
Request Body:
{
"token": "tok_abc123...",
"paymentType": "card"
}
| Field | Type | Required | Description |
|---|---|---|---|
| token | string | Yes | Payment token from TalusPay tokenizer |
| paymentType | string | No | card (default) or ach |
Response (200):
{
"message": "Payment method updated successfully",
"subscriptionStatus": "ACTIVE",
"paymentMethodLast4": "4242"
}
Response when reactivating a PAYMENT_FAILED subscription (200):
{
"message": "Payment method updated and subscription reactivated",
"subscriptionStatus": "ACTIVE",
"paymentMethodLast4": "4242",
"amountCharged": 4000,
"transactionId": "txn_abc123",
"billingDayOfMonth": 21
}
amountCharged is in cents (0 with no transactionId when the company's custom pricing totals $0). billingDayOfMonth is the new billing day.
Response when the recovery charge is declined (402):
{
"message": "Payment declined",
"details": "Insufficient funds"
}
The subscription remains PAYMENT_FAILED; the client should prompt for a different payment method.
paymentMethodLast4 is the last 4 digits of the newly stored card/bank account, or null if TalusPay did not surface it.
Error Responses:
400- No active or payment-failed subscription found, missing fields, or a payment gateway error ("Payment error: ...")401- Unauthorized402- The recovery charge on aPAYMENT_FAILEDsubscription was declined (subscription staysPAYMENT_FAILED)403- Not an admin employee502- Failed to store new payment method in TalusPay vault
POST /saas/cancel
Cancels the company's SaaS subscription.
- For
ACTIVEsubscriptions, the status remainsACTIVEand the subscription is flagged withcancelAtPeriodEnd: true. The status flips toCANCELLEDautomatically on the next billing day (i.e., at the end of the paid-up period) — no further charges are made. The stored payment method is retained until finalization so the customer canPOST /saas/reactivateduring the grace period without re-entering their card. - For
PAYMENT_FAILEDsubscriptions, the status flips toCANCELLEDimmediately and the stored payment method is deleted from the TalusPay vault, since there is no paid-up period to honor.
Authentication: Bearer token (ADMIN only)
Request Body: None
Response (200) — ACTIVE subscription scheduled to cancel at period end:
{
"message": "Subscription scheduled to cancel at period end",
"subscriptionStatus": "ACTIVE",
"cancelAtPeriodEnd": true,
"cancelledAt": "2026-04-02T15:30:00.000Z"
}
Response (200) — PAYMENT_FAILED subscription cancelled immediately:
{
"message": "Subscription cancelled successfully",
"subscriptionStatus": "CANCELLED",
"cancelledAt": "2026-04-02T15:30:00.000Z"
}
Error Responses:
401- Unauthorized403- Not an admin employee404- No subscription found409- Subscription is already cancelled or already scheduled to cancel
POST /saas/reactivate
Reactivates a subscription that was scheduled to cancel at period end, as if the cancellation had never happened. Clears the cancelAtPeriodEnd flag and cancelledAt timestamp. The stored payment method from the vault is reused, so no tokenization is needed. Only works during the grace period — once the subscription has already finalized to CANCELLED, a full re-subscribe via POST /saas/subscribe is required instead.
Authentication: Bearer token (ADMIN only)
Request Body: None
Response (200):
{
"message": "Subscription reactivated successfully",
"subscriptionStatus": "ACTIVE",
"cancelAtPeriodEnd": false
}
Error Responses:
401- Unauthorized403- Not an admin employee404- No subscription found409- Subscription is not scheduled to cancel (nothing to reactivate)
GET /saas/pricing
Returns the SaaS pricing for the authenticated company. Returns custom pricing if configured, otherwise default pricing.
Authentication: Bearer token
Response (200):
{
"basePrice": 4500,
"additionalUserPrice": 3000,
"isCustomPricing": false
}
| Field | Type | Description |
|---|---|---|
| basePrice | number | Price in cents for the first user |
| additionalUserPrice | number | Price in cents for each additional user |
| isCustomPricing | boolean | Whether this company has custom pricing |
GET /saas/subscription
Returns the current SaaS subscription details for the authenticated company. Returns the same subscription object included in the login response.
Authentication: Bearer token
Response (200):
{
"status": "ACTIVE",
"tradesmenTechPublicKey": "pub_xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"freeTrialEndDate": null,
"hasPaymentMethod": true,
"paymentMethodLast4": "4242",
"billingDayOfMonth": 15,
"maxEmployees": 5,
"lastPaymentDate": "2026-04-01T09:00:00.000Z",
"lastPaymentAmount": 11500,
"cancelAtPeriodEnd": false,
"cancelledAt": null,
"pricing": {
"basePrice": 4500,
"additionalUserPrice": 3000,
"isCustomPricing": false
}
}
| Field | Type | Description |
|---|---|---|
| status | string | NEVER_SUBSCRIBED, ACTIVE, PAYMENT_FAILED, or CANCELLED. If the underlying subscription is CANCELLED but the company still has an unexpired free trial (today is strictly before freeTrialEndDate), the effective status is reported as ACTIVE for the duration of the trial. |
| tradesmenTechPublicKey | string or null | TalusPay public key for tokenizing SaaS payments |
| freeTrialEndDate | string or null | Trial end date (YYYY-MM-DD), or null if no trial |
| hasPaymentMethod | boolean | Whether the company has a card on file |
| paymentMethodLast4 | string or null | Last 4 digits of the card/bank account on file, or null if unknown (e.g. subscriptions created before this field existed) |
| billingDayOfMonth | number or null | Day of month for recurring billing, or null if not subscribed |
| maxEmployees | number or null | Subscribed employee limit, or null if not subscribed |
| lastPaymentDate | string or null | ISO timestamp of most recent charge, or null |
| lastPaymentAmount | number or null | Most recent charge in cents, or null |
| cancelAtPeriodEnd | boolean | true when cancel was requested and status will flip to CANCELLED on the next billing day |
| cancelledAt | string or null | ISO timestamp of when cancel was requested, or null |
| pricing.basePrice | number | Price in cents for the first user |
| pricing.additionalUserPrice | number | Price in cents for each additional user |
| pricing.isCustomPricing | boolean | Whether this company has a custom rate |
Subscription Object in Login Response
The login endpoint (POST /accounts/login) includes a subscription object with all SaaS details:
{
"subscription": {
"status": "ACTIVE",
"tradesmenTechPublicKey": "pub_xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"freeTrialEndDate": "2026-05-01",
"hasPaymentMethod": true,
"paymentMethodLast4": "4242",
"billingDayOfMonth": 15,
"maxEmployees": 5,
"lastPaymentDate": "2026-04-01T09:00:00.000Z",
"lastPaymentAmount": 11500,
"cancelAtPeriodEnd": false,
"cancelledAt": null,
"pricing": {
"basePrice": 4500,
"additionalUserPrice": 3000,
"isCustomPricing": false
}
}
}
| Field | Type | Description |
|---|---|---|
| status | string | NEVER_SUBSCRIBED, ACTIVE, PAYMENT_FAILED, or CANCELLED. If the underlying subscription is CANCELLED but the company still has an unexpired free trial (today is strictly before freeTrialEndDate), the effective status is reported as ACTIVE for the duration of the trial. |
| tradesmenTechPublicKey | string or null | TalusPay public key for tokenizing SaaS payments |
| freeTrialEndDate | string or null | Trial end date (YYYY-MM-DD), or null if no trial |
| hasPaymentMethod | boolean | Whether the company has a card on file |
| paymentMethodLast4 | string or null | Last 4 digits of the card/bank account on file, or null if unknown (e.g. subscriptions created before this field existed) |
| billingDayOfMonth | number or null | Day of month for recurring billing, or null if not subscribed |
| maxEmployees | number or null | Subscribed employee limit, or null if not subscribed |
| lastPaymentDate | string or null | ISO timestamp of most recent charge, or null |
| lastPaymentAmount | number or null | Most recent charge in cents, or null |
| cancelAtPeriodEnd | boolean | true when cancel was requested and status will flip to CANCELLED on the next billing day |
| cancelledAt | string or null | ISO timestamp of when cancel was requested, or null |
| pricing.basePrice | number | Price in cents for the first user |
| pricing.additionalUserPrice | number | Price in cents for each additional user |
| pricing.isCustomPricing | boolean | Whether this company has a custom rate |
Daily Billing (Cron)
A scheduled process runs daily at 9:00 AM UTC to process monthly SaaS billing:
- Scans all
ACTIVEsubscriptions - For each company whose
billingDayOfMonthmatches today:- If
cancelAtPeriodEndis set, the subscription is finalized toCANCELLEDand the stored payment method is deleted from the vault — nothing is charged. - If the subscription's free trial is still active (today is strictly before
freeTrialEndDate), the company is skipped. - Counts actual billable employees in the database. Employees with
hasAppAccess: falsehave no app access and are excluded from this count, so they are never charged a per-seat fee. (Employees created beforehasAppAccessexisted are treated as having access and are counted.) - Reduces
maxEmployeesto the actual billable count if fewer billable employees exist - Calculates the monthly charge based on the adjusted employee count. A $0 total (custom pricing) is recorded as paid (
lastPaymentAmount: 0) without contacting the gateway. - Charges the stored payment method via the TalusPay vault
- On success: updates
lastPaymentDateand adjustedmaxEmployees - On a declined charge: sets
subscriptionStatustoPAYMENT_FAILEDand emails the company (the company'semail) that the payment was declined and how to update the payment method; the support inbox is notified separately. The subscription returns toACTIVEonly through a successful charge viaPUT /saas/payment-method. - A subscription already charged earlier the same UTC day (a same-day subscribe or recovery charge) is skipped, so it is never billed twice in one day.
- If the attempt itself errors (gateway or database failure), the subscription is left untouched (still
ACTIVE, not retried until next month) and only the support inbox is notified.
- If
If the billing day exceeds the number of days in the current month (e.g., billing day 31 in a 28-day month), the charge occurs on the last day of the month.