Skip to main content
This document is for new merchants. It provides a structured overview of all key points required to integrate with the EasyBilling billing platform, including environment setup, API workflows, field mapping notes, and common pitfalls.

1. Overview

EasyBilling is the subscription billing platform used by this system. It is responsible for:
  • Managing customer accounts and subscription contracts
  • Supporting usage-based billing
  • Processing actual payments through Stripe Connect
  • Providing invoice generation and a customer self-service portal
Sandbox Base URL:
https://sbx.api.easybilling.cloud/billing
Production Base URL:
https://app.api.easybilling.cloud/billing
All requests must include these headers:
  • Authorization: Bearer <EASYBILLING_API_TOKEN>
  • trace-id: <UUID>

2. Environment Variable Configuration

Required:
VariableDescription
EASYBILLING_BASE_URLAPI base URL (sandbox: https://sbx.api.easybilling.cloud/billing)
EASYBILLING_API_TOKENAPI key obtained from EasyBilling
EASYBILLING_DEFAULT_PLAN_IDDefault (free/starter) plan UUID
EASYBILLING_UPGRADE_PLAN_IDPaid upgrade plan UUID
EASYBILLING_USAGE_SCHEMA_NAMEUsage event schema name. Must be defined in EasyBilling first
EASYBILLING_PAYMENT_SUCCESS_URLRedirect URL after Stripe payment success
EASYBILLING_PAYMENT_CANCEL_URLRedirect URL after Stripe payment cancellation
EASYBILLING_CUSTOMER_PORTAL_URLCustomer portal base URL (sandbox: https://sbx.app.easybilling.cloud/customer/portal). EasyBilling also supports custom domains, e.g. https://billing.yourcompany.com/customer/portal
EASYBILLING_INVOICE_TEMPLATE_IDInvoice PDF template UUID

3. Account Creation

When a user registers, create the corresponding account in EasyBilling. Endpoint: POST /api/accounts Request body:
{
  "name": "User Name",
  "number": "SM-ACC-00000001",
  "email": "user@example.com",
  "addressLine1": "123 Main St",
  "addressLine2": "",
  "country": "US",
  "state": "CA",
  "city": "San Francisco",
  "postalCode": "94102"
}
Key notes:
  • The account number field name is number, not accountNumber.
  • The account number should use your own system’s customer account number.
  • If you do not pass an account number, EasyBilling will generate its own.
  • If you do not use your own customer account number, you must store EasyBilling number in your user table. All follow-up EasyBilling operations depend on this field.

4. Contract Creation

After registration (or on demand), create a contract for the default plan. Endpoint: POST /api/contract-actions Request body:
{
  "accountNumber": "SM-ACC-00000001",
  "actions": [
    {
      "type": "create-contract-with-plan",
      "createContractWithPlan": [
        {
          "planId": "<EASYBILLING_DEFAULT_PLAN_ID>",
          "effectiveDate": "2026-04-13",
          "currency": ["USD"]
        }
      ],
      "immediatelyPay": true,
      "paymentInfo": {
        "paymentGatewayType": "stripe-connect",
        "paymentSuccessUrl": "<EASYBILLING_PAYMENT_SUCCESS_URL>",
        "paymentCancelUrl": "<EASYBILLING_PAYMENT_CANCEL_URL>"
      }
    }
  ]
}
Key notes:
  • effectiveDate must be today in YYYY-MM-DD format. Do not use a fixed date such as the first day of a month.
  • Set expirationDate as needed. For a one-year contract, set one year later (for example, 2027-04-13).
  • expirationDate means the contract expires at 00:00 on that date, so that date is not included.
  • createContractWithPlan must be an array.
Response (must be persisted):
{
  "contractActionNumber": "CA-000001",
  "contractInfo": {
    "id": "contract-uuid",
    "contractNumber": "CT-000001",
    "status": "active"
  },
  "paymentResults": []
}
Persist contractInfo.id to your user table as easyBillingContractId. This field is required for both upgrade and cancellation.

5. Plan Upgrade

Switch a user from the current plan to a paid plan. Endpoint: POST /api/contract-actions Request body:
{
  "accountNumber": "SM-ACC-00000001",
  "actions": [
    {
      "type": "switch-plan",
      "switchPlan": {
        "contractId": "<easyBillingContractId>",
        "planId": "<EASYBILLING_UPGRADE_PLAN_ID>",
        "effectiveDate": "2026-04-13",
        "currency": ["USD"]
      },
      "immediatelyPay": true,
      "paymentInfo": {
        "paymentGatewayType": "stripe-connect",
        "paymentSuccessUrl": "<EASYBILLING_PAYMENT_SUCCESS_URL>",
        "paymentCancelUrl": "<EASYBILLING_PAYMENT_CANCEL_URL>"
      }
    }
  ]
}
Response handling:
{
  "contractActionNumber": "CA-000002",
  "paymentResults": [
    {
      "sessionUrl": "https://checkout.stripe.com/..."
    }
  ]
}
Extract the Stripe Checkout URL from paymentResults[].sessionUrl and return it to the frontend. Recovery path (when contractId is empty): If contract creation failed during registration and contractId is empty, first create a contract directly with the target upgrade plan (skip switch-plan). Then extract sessionUrl from the response.

6. Contract Cancellation

Cancel the active contract immediately. Endpoint: POST /api/contract-actions Request body:
{
  "accountNumber": "SM-ACC-00000001",
  "actions": [
    {
      "type": "cancel",
      "cancel": {
        "contractId": "<easyBillingContractId>",
        "effectiveDate": "{{today()+1}}"
      }
    }
  ]
}
Notes:
  • Set effectiveDate to tomorrow (today + 1 day). Cancellation takes effect on the next day.
  • If today’s usage has already been uploaded, the earliest possible cancellation is tomorrow.
  • EasyBilling automatically handles refunds and tax reversal. No separate backend calculation is required.
  • After cancellation succeeds, update user subscriptionStatus to CANCELED in your own system.

7. Usage Event Reporting

Whenever a user completes a billable action (for example, one AI analysis), report usage to EasyBilling. Endpoint: POST /api/usage-events Important: The request body must be an array.
[
  {
    "eventId": "uuid-v4",
    "schemaName": "speech-master",
    "eventTime": "2026-04-13T08:00:00.000Z",
    "accountNumber": "SM-ACC-00000001",
    "attributes": [
      { "name": "quantity", "value": "1" }
    ]
  }
]
Key notes:
  • eventTime must be ISO 8601 UTC format.
  • Use UUID v4 for eventId to ensure idempotency.
  • Asynchronous reporting is recommended. On failure, log the error in your business table and do not block the main flow.
  • attributes must match the usage event schema definition. The sample above is only an example.

8. Invoice List Query

Endpoint: GET /api/invoices?accountNumber=SM-ACC-00000001 Response field mapping (important):
EasyBilling FieldMeaningSuggested Mapping
numberInvoice number (e.g. INV-000001)invoiceNumber
idInvoice UUIDinvoiceId
dateInvoice dateinvoiceDate
totalAmountTotal amount (numeric)amount
dueDateDue datedueDate
currencyCurrencycurrency

9. Invoice PDF Generation

Endpoint: POST /template-engine/api/pdf/generate Request body:
{
  "name": "INV-000000325",
  "objectId": "9efc7d38-0d97-4cc3-a861-fdf4613d9d75",
  "objectType": "invoice",
  "templateId": "<EASYBILLING_INVOICE_TEMPLATE_ID>"
}
Notes:
  • name should use the invoice number field, i.e. invoiceNumber.
  • objectId should use the invoice id field, i.e. invoiceId.
  • Before calling PDF API, verify the invoice belongs to the current user account by checking the invoice list.
  • The response id is pdfId. Download PDF via GET /template-engine/api/pdf/{pdfId}.

10. Customer Portal

The customer portal allows users to self-manage subscriptions and view invoices.

Step 1: Get a Short-lived Token

Endpoint: POST /api/authenticate/account-auth
{
  "accountNumber": "SM-ACC-00000001"
}
Token field compatibility (check in priority order):
response.token
response.accessToken
response.accountToken
response.data.token
response.data.accessToken
response.data.accountToken
Only log the first 6 characters of the token. Never output the full token.

Step 2: Build the Portal URL

https://sbx.app.easybilling.cloud/customer/portal?token=<TOKEN>
Use URL API to build safely and avoid encoding issues from manual string concatenation:
const portalUrl = new URL(env.easyBillingCustomerPortalUrl); // EASYBILLING_CUSTOMER_PORTAL_URL
portalUrl.searchParams.set('token', token);
return portalUrl.toString();
Important: The portal URL contains sensitive token data. It must be returned by a backend endpoint and must not be hardcoded or persisted on frontend.

11. Common Notes

#IssueCorrect Approach
1effectiveDate set to start of month (e.g. 2026-04-01)Always use today’s date
2Reading accountNumber from account creation responseResponse field is number
3Treating account creation and contract creation as one stepIf account creation succeeds but contract creation fails, retry contract creation separately
4Forgetting array wrapper for usage event bodyPOST /api/usage-events body must be [event]
5Not handling token field variantsCheck all 6 candidate locations in account-auth response
6Generating PDF without ownership verificationConfirm (name, objectId) exists in current user’s invoice list first
7Calling switch-plan when contractId is emptyUse recovery path: create contract first, then upgrade

Quick Checklist

For new project integration, verify:
  • Environment variables are configured (8 required items)
  • Account creation response uses number, not accountNumber
  • Contract creation uses today’s effectiveDate
  • contractInfo.id is persisted in user table
  • Usage event body is an array
  • account-auth token extraction supports all 6 response formats
  • Portal URL containing token is returned only from backend