LedgerBee Developer
  • Getting started
  • Conventions
  • Products
  • Advisor firms
  • Configuration
  • API Reference
Information
Accounts
    List accountsgetCreate an accountpostGet an accountgetDelete an accountdeleteUpdate an accountpatch
Advisor Authority Extracts
    Submit authority extract data for an advisor firm's clientspost
Advisor Clients
    List the advisor firm's clientsget
API Key
    Get current API keyget
Authority Extracts
    Submit authority extract datapost
Bank Reconciliations
    Reconcile bank lines against entriespostUndo a bank reconciliationpostCheck what undoing a reconciliation would dopostReconcile a batch of matchespostCheck what reconciling a batch of matches would dopostCheck what reconciling bank lines against entries would dopost
Bank Transactions
    List bank linesgetGet a bank linegetDismiss bank lines from reconciliationpostCheck which bank lines a dismiss would changepostRestore dismissed bank lines to reconciliationpostCheck which bank lines a restore would changepost
Billing Groups
    Form a billing grouppostGet a billing groupgetAdd members to a billing grouppostRemove a member from a billing groupdeleteCheck billing group eligibilitypost
Budgets
    List budgetsgetGet a budgetgetGet the budget vs actuals comparisongetExport a budget's Excel workbookgetOverwrite a budget's figures from an edited workbookpostList a budget's frozen baselinesgetGet a frozen baseline with its snapshot cellsgetList a budget's re-baseline proposalsgetList a budget's scenariosgetResolve a budget's grid under a scenariogetGet the variance report vs a frozen baselinegetGet the runway headlineget
Checkout
    Confirm the checkoutpostQuote a first periodpostIntegration readinessgetMint a checkout sessionpostRehydrate a sessiongetRelease the card hold (edit-after-card)postPoll card statusgetOpen the card windowpostOpen a card window for a live subscriptionpost
Company
    Get company detailsget
Connected app OAuth
    JSON Web Key Set used to verify OAuth access-token signaturesgetRFC 8414 authorization-server metadata for the connected-app OAuth servergetRFC 9728 protected-resource metadata for an MCP resourcegetRFC 9728 protected-resource metadata for an MCP resourcegetOpenID Connect discovery document for the connected-app OAuth serverget
Credit Note Links
    Link a credit note to the invoice it creditspostCheck a credit note’s links and the invoices it can be linked topostDetach a credit note from the invoices it is applied topost
Credit Notes
    List credit notesgetCreate a credit notepostGet a credit notegetGet the delivery status of a credit notegetDownload the credit note PDFgetSend a credit note to the customerpostCredit a whole invoicepost
Customers
    List customersgetCreate a customerpostGet a customergetDelete a customerdeleteUpdate a customerpatchList a customer's contactsgetList a customer's departmentsgetList customer groupsget
Dimensions
    List all dimensionsgetCreate a new dimension categorypostGet a dimensiongetUpdate a dimension categoryputDelete a dimension categorydeleteList distribution keys (paginated)getCreate a distribution keypostGet a distribution keygetList dimension values (paginated)getCreate a new dimension valuepostUpdate a dimension valueputDelete a dimension valuedelete
Discounts
    List discountsgetCreate a discountpostGet a discountgetDelete a discountdeleteUpdate a discountpatchSet a discount's amount in one currencyputRemove a discount's amount in one currencydeleteCheck whether a discount applies to a product for a customer on a daygetAssign a discountpostRemove an assignmentdeleteUpdate an assignmentpatchList a discount's codesgetAdd a code to a discountpostDelete a codedeleteUpdate a codepatchList the discounts that apply to a product for a customer on a daygetCheck a cartpostLook up a discount codeget
Document Templates
    List document templatesget
Document Upload Links
    Upload a file through a minted linkpost
Download Links
    Mint a download link for a document PDFgetDownload a minted linkget
Draft Journal Entries
    Create multiple draft journal entries in batchpostList draft journal entriesgetCreate a draft journal entrypostGet a draft journal entrygetDelete a draft journal entrydeleteBook a draft journal entrypost
Draft Journal Entries (v2)
    Create draft journal entries in batch (v2)postList draft journal entries (v2)getCreate a draft journal entry (v2)postGet a draft journal entry (v2)getDelete a draft journal entry (v2)deleteUpdate a draft journal entry (v2)patchGet attachments for a draft journal entry (v2)getAdd a document to a draft journal entry (v2)postRemove a document from a draft journal entry (v2)deleteBook a draft journal entry (v2)post
Entitlements
    List entitlementsgetCreate an entitlementpostGet an entitlementgetDelete an entitlementdeleteUpdate an entitlementpatch
Invoices
    List invoicesgetCreate a draft invoicepostGet an invoicegetDelete a draft invoicedeleteUpdate an unsent invoicepatchGet the delivery status of an invoicegetDownload the invoice PDFgetSend an invoice to the customerpost
Journal Categories
    List journal categoriesgetCreate a journal categorypostUpdate a journal categoryputDelete a journal categorydelete
Journal Entries
    List journal entriesgetGet a journal entrygetUpdate a journal entry — correct the reference and/or set your external system idpatchGet attachments for a journal entrygetAdd a document to a journal entrypostRemove a document from a journal entrydeletePreview a correction without posting itpostMove postings to different accounts, keeping the document intactpostRebuild the entry a reversal undid, as a draftpostPreview rebuilding the entry a reversal undidpostReverse a posted entry and open a draft to re-enter itpostReverse posted journal entries in batchpostPreview reversing posted journal entries in batchpostReverse a posted journal entrypostPreview reversing a posted journal entrypost
Journal Entries (v2)
    Create a journal entry (v2)postCreate journal entries in batch (v2)post
MCP
    LedgerBee Developer MCP Serverpost
Meters
    List meter subscriptions by IDgetReport usagepostList meter subscriptions by nameget
Open Entries
    List a counterparty’s open entriesget
Order Confirmations
    List order confirmationsgetCreate a draft order confirmationpostGet an order confirmationgetUpdate a draft order confirmationpatchConvert an order confirmation into an invoicepostDownload an order confirmation as PDFgetSend an order confirmationpost
Payment Methods
    List saved payment methods for a customergetCancel a saved card on the payment providerdeleteUnassign a payment method from a customerdeleteGenerate a link for the customer to save a card for future paymentspostSet a saved payment method as the customer defaultput
Portal Plans
    List the full plan cataloguegetGet a plangetResolve the gated pricing catalogue for an identified buyer (partner display)post
Portal SSO
    Get a tenant's SSO signing keys (JWKS)getMint a checkout-vouch token (partner-vouched anonymous checkout)postMint a customer-portal SSO handoff referencepostProvision a customer + grant portal access (partner JIT provisioning)postRevoke (force-refresh) a user's customer-portal sessionspost
Product Groups
    List product groupsgetCreate a product grouppostGet a product groupgetDelete a product groupdeleteUpdate a product grouppatch
Product Prices
    Create a product pricepostGet a product pricegetDelete a product pricedeleteUpdate a product pricepatchActivate a product pricepostArchive a product pricepostDisable a product pricepostSet a price as the product defaultpost
Products
    List productsgetCreate a productpostGet a productgetDelete a productdeleteUpdate a productpatchArchive a productpost
Projects
    List all projectsgetCreate or update a project by external referenceputCreate a projectpostGet a projectgetUpdate a projectputGet project profitgetAdd a subprojectpostUpdate a subprojectputDelete a subprojectdelete
Quotes
    List quotesgetCreate a draft quotepostGet a quotegetUpdate a draft quotepatchConvert a quotepostDownload a quote as PDFgetSend a quotepost
Settlements
    List a counterparty’s settlementsgetSettle open entries against each otherpostGet a settlementgetUndo a settlementpostCheck what undoing a settlement would dopostCheck what settling these entries would dopost
Shipments
    List shipmentsgetCreate a shipment from an orderpostGet a shipmentgetCancel a shipmentpostDispatch a shipmentpost
Stock
    List stock movementsgetList on-hand stockgetOn-hand for one productget
Subscriptions
    List customer subscriptionsgetAssign a subscription to a customerpostGet a customer subscription by its stable idgetUpdate a customer subscriptionpatchAdd an add-on to a customer subscriptionpostAttach existing subscriptions as add-onspostCheck whether subscriptions can become add-onspostChange the products on a customer subscriptionpostRetry a failed card paymentpostList a subscription's pending scheduled changesgetCancel a single pending scheduled changedeleteGet a subscription's unbilled usagegetCancel a customer subscriptionpostList subscription plansgetCreate a subscription planpostArchive a subscription planpost
Suppliers
    List suppliersgetCreate a supplierpostDelete a supplierdeleteList supplier contactsgetList supplier departmentsgetList supplier groupsget
VAT Codes
    List VAT codesgetCreate a VAT codepostGet a VAT codegetDelete a VAT codedeleteUpdate a VAT codepatch
VAT periods
    Record a VAT return filed outside LedgerBeepostPreview recording a VAT return filed outside LedgerBeepostSettle a filed VAT periodpostPreview a VAT period settlementpost
Vendors
    List vendorsgetCreate a vendorpostList vendor contactsgetList vendor departmentsgetList vendor groupsget
Webhook Endpoints
    List webhook endpointsgetCreate a webhook endpointpostRetrieve a webhook endpointgetUpdate a webhook endpointputDelete a webhook endpointdeleteRoll the signing secretpostSend a test eventpost
Schemas
LedgerBee Public API
LedgerBee Public API

Checkout

Download schema

Confirm the checkout

POST
https://api.ledgerbee.com/api
/v1/checkout/confirm
x-api-key (header)
or
OAuth 2.0

Credential: a company's API key or OAuth token.

Consumes the session and writes everything, transactionally: the customer (created, or your existingCustomerId reused), the consent evidence (recorded against the SESSION's pinned versions with PARTNER_ASSERTED provenance), the subscription, and the first charge. Synchronous — the subscription id is in the response.

x-api-idempotency-key is REQUIRED (400 IDEMPOTENCY_KEY_REQUIRED without it). A retry with the same key replays the full original response; a concurrent duplicate answers 409 IDEMPOTENT_REQUEST_IN_PROGRESS; the same key reused for a DIFFERENT session answers 422 IDEMPOTENCY_KEY_REUSED.

Consent is assertion (you presented the pinned documents in your UI): termsAccepted: true is required, and recurringConsentAccepted: true on the CARD rail. On CARD, confirm requires the session's card to be CARD_READY — or a cardHandoffToken carried from an expired session.

Refusals to build the retry loop around: a 410 means the pinned plan/terms changed or the session expired (re-mint); PORTAL_CHECKOUT_AUTHORIZED_AMOUNT_CHANGED means the engine re-run no longer matches the pinned amount (card-release → re-quote → re-mint → re-confirm).

Invoice rail: the first invoice is billed asynchronously (billingPending: true). A tenant that serves no hosted portal sends invoice emails WITHOUT an online pay-now link — payment instructions ride the invoice document itself.

Required Scope

  • checkout

Confirm the checkout › Headers

x-api-idempotency-key
​string · maxLength: 255

Optional idempotency key for safely retrying mutating requests.

Confirm the checkout › Request Body

CheckoutConfirmRequest
sessionId
​string · required

The session to confirm. Single-use: consumed whatever the outcome.

paymentMethod
​string · enum · required

The payment rail the buyer chose.

Enum values:
CARD
INVOICE
termsAccepted
​boolean · required

Your assertion that the buyer accepted the pinned terms on your surface. Must be true — false/absent refuses with PORTAL_CHECKOUT_CONSENT_REQUIRED.

acceptedAt
​string · required

When the buyer accepted (ISO 8601). Evidence, not authority — implausible instants (future, or older than an hour) are replaced with the server’s own clock.

recurringConsentAccepted
​boolean

Your assertion that the buyer accepted recurring billing. REQUIRED true on the CARD rail.

cardHandoffToken
​string

A card handoff token carried from an EXPIRED session (the edit-after-card loop) — the captured card survives into this confirm. Defaults to the card window this session opened.

Confirm the checkout › Responses

CheckoutConfirmResponse
subscriptionId
​string · uuid · required

The created subscription.

reference
​string | null · required

Your reference, echoed.

billingPending
​boolean · required

True when the first invoice is billed asynchronously after this response (INVOICE rail, and CARD confirms whose charge is queued). Listen for subscription.billed / poll the subscription.

POST/v1/checkout/confirm
curl https://api.ledgerbee.com/api/v1/checkout/confirm \ --request POST \ --header 'Content-Type: application/json' \ --header 'x-api-key: <api-key>' \ --data '{ "sessionId": "string", "paymentMethod": "CARD", "termsAccepted": true, "recurringConsentAccepted": true, "acceptedAt": "string", "cardHandoffToken": "string" }'
Example Request Body
{ "sessionId": "string", "paymentMethod": "CARD", "termsAccepted": true, "recurringConsentAccepted": true, "acceptedAt": "string", "cardHandoffToken": "string" }
json
application/json
Example Responses
{ "subscriptionId": "00000000-0000-0000-0000-000000000000", "reference": "reference", "billingPending": true }
json
application/json

Quote a first period

POST
https://api.ledgerbee.com/api
/v1/checkout/quote
x-api-key (header)
or
OAuth 2.0

Credential: a company's API key or OAuth token.

Pure read: first-period pricing including exact VAT for the buyer you describe, the terms bodies and recurring-billing disclosure context, start-date rules, allowedPaymentMethods, and cardPaymentsEnabled — which is chargeability-aware, so a card step is never offered in a currency the window would refuse. firstPeriodChargeable: false means a zero first period (free trial / 100% discount), a discount code that takes the first period below what a card can be charged, or a subscription that bills in arrears (its first invoice is charged to the saved card on firstInvoiceDate): adapt your copy ("no charge today"); the card window still opens save-only. Only a first invoice a discount code takes below what a card can be charged is paid by bank transfer; in arrears the first invoice is charged to the saved card on firstInvoiceDate.

Pass discountCode to price a code the buyer typed: quote.discount carries the code, the discount's name and type (percentage, fixed or per_unit), what it takes off the first period before VAT (firstPeriodAmountOff; quote.plan.items keep the regular price, quote.pricing is net of it), the day the regular price starts (endsAt, null when it never ends) and firstPeriodChargedToCard. A code that is unknown, used up or not for this plan is refused with its DISCOUNT_* code.

Pass billingDirection (advance or arrears) to choose when the buyer pays; absent, the company's default applies. The response states the direction and firstInvoiceDate: with advance the first period is invoiced at confirm, with arrears nothing is invoiced at confirm and the first invoice comes when the first period ends. quote.pricing is the first period either way.

country is required so VAT resolves exactly; consumer-facing prices MUST be displayed including VAT (render the gross figures). A vatNumber is accepted for BUSINESS buyers only and is checked against the country's published format.

A STRIPE_CROSS_CURRENCY_NOT_ENABLED refusal later in the flow is a configuration issue on your Stripe account (enable cross-currency charges or add a bank account in that currency on Stripe), never a buyer error — cardPaymentsEnabled: false here is how you avoid offering that dead end.

Required Scope

  • checkout

Quote a first period › Headers

x-api-idempotency-key
​string · maxLength: 255

Optional idempotency key for safely retrying mutating requests.

Quote a first period › Request Body

CheckoutQuoteRequest
planVersionId
​string · uuid · required

The plan version to quote (from the catalogue).

planItemId
​string · uuid · required

The pricing-card item on that version.

country
​string · required

Buyer country, ISO 3166-1 alpha-2 — REQUIRED so VAT resolves exactly.

Example: DK
customerType
​string · enum · required

Whether the buyer is a business or a private person.

Enum values:
BUSINESS
PRIVATE_PERSON
vatNumber
​string

The buyer’s VAT number (BUSINESS only — refused otherwise).

startDate
​string

Requested start date (YYYY-MM-DD). Defaults to today; never in the past.

currency
​string

Presentment currency (ISO 4217). Must be in the card’s availableCurrencies; refused with PORTAL_CHECKOUT_CURRENCY_NOT_AVAILABLE otherwise. Absent → the card’s own currency.

Example: DKK
​CheckoutQuantitySelection[]

Buyer-chosen quantities for quantity-bearing products.

​CheckoutAddonSelection[]

Add-ons the buyer takes with the plan, each named by the catalogue item’s addons[].planId, with optional quantities. An add-on checkout sells bills at the plan’s period, on the same invoice as the plan. The same planId twice is refused with VALIDATION_FAILED. Absent or empty → the plan alone.

discountCode
​string · maxLength: 64

A discount code the buyer typed. Priced onto the first period (quote.discount states what it takes off, until when, and whether the first period is charged to the card) and attached to the subscription for its periods. An unknown, used-up or inapplicable code is refused with its DISCOUNT_* code; each request naming a code spends one use of the API key’s code-attempt budget (429 DISCOUNT_CHECK_RATE_LIMITED).

Example: WELCOME10
billingDirection
​string · enum

Whether the subscription bills each period in advance or in arrears. advance: the first period is invoiced on firstInvoiceDate, which is at confirm for a start date of today. arrears: nothing is invoiced at confirm, and the first invoice comes when the first period ends (firstInvoiceDate). Absent → the company’s default billing direction. The session pins the direction; confirm creates the subscription in it.

Enum values:
advance
arrears
Example: advance
language
​string · enum

Language for display texts, terms and the disclosure.

Enum values:
en
da

Quote a first period › Responses

CheckoutQuoteResponse
quote
​object · required

First-period quote — the SAME payload the hosted portal renders (display parity is structural): plan title/description + display lines, pricing (subtotal, per-rate VAT breakdown, total, currency), quantity rows, the quantity rows of every add-on the card offers (addonQuantityRows, each naming its add-on by planId; addonSubscriptionId carries the same value), terms bodies, the resolved start date, allowed payment methods and cardPaymentsEnabled. With a discountCode, discount states what the code takes off the first period before VAT (firstPeriodAmountOff), the day the regular price starts (endsAt, null when it never ends) and whether the discounted first period is charged to the card (firstPeriodChargedToCard); plan.items keep the regular price and pricing is net of the discount. Null without a code.

firstPeriodChargeable
​boolean · required

False when the first period nets to zero (free trial / 100% discount), when a discount code takes it below what a card can be charged while the regular price is not, or when the subscription bills in arrears (its first invoice is charged to the saved card on firstInvoiceDate). The card window still opens save-only — the card is stored for the first real charge and nothing is authorized ("no charge today"). A first invoice a discount code takes below the card minimum is then paid by bank transfer and the card is charged from the first full-price period; in arrears the first invoice is charged to the saved card on firstInvoiceDate.

billingDirection
​string · enum · required

The direction the subscription would bill in: the request’s billingDirection, else the company’s default.

Enum values:
advance
arrears
firstInvoiceDate
​string · required

The day the first invoice is issued (YYYY-MM-DD). advance: today for a start date of today, or the start date less the company’s send offset for a later one. arrears: the end of the first period. The first invoice bills the first period quote.pricing states.

Example: 2026-11-15
POST/v1/checkout/quote
curl https://api.ledgerbee.com/api/v1/checkout/quote \ --request POST \ --header 'Content-Type: application/json' \ --header 'x-api-key: <api-key>' \ --data '{ "planVersionId": "3f2b6f1e-8c4d-4e0b-9d5a-7a1c2e3f4b5d", "planItemId": "3f2b6f1e-8c4d-4e0b-9d5a-7a1c2e3f4b5d", "country": "DK", "customerType": "BUSINESS", "vatNumber": "string", "startDate": "string", "currency": "DKK", "quantities": [ { "priceId": "3f2b6f1e-8c4d-4e0b-9d5a-7a1c2e3f4b5d", "quantity": 0 } ], "addons": [ { "planId": "3f2b6f1e-8c4d-4e0b-9d5a-7a1c2e3f4b5d", "quantities": [] } ], "discountCode": "WELCOME10", "billingDirection": "advance", "language": "en" }'
Example Request Body
{ "planVersionId": "3f2b6f1e-8c4d-4e0b-9d5a-7a1c2e3f4b5d", "planItemId": "3f2b6f1e-8c4d-4e0b-9d5a-7a1c2e3f4b5d", "country": "DK", "customerType": "BUSINESS", "vatNumber": "string", "startDate": "string", "currency": "DKK", "quantities": [ { "priceId": "3f2b6f1e-8c4d-4e0b-9d5a-7a1c2e3f4b5d", "quantity": 0 } ], "addons": [ { "planId": "3f2b6f1e-8c4d-4e0b-9d5a-7a1c2e3f4b5d", "quantities": [] } ], "discountCode": "WELCOME10", "billingDirection": "advance", "language": "en" }
json
application/json
Example Responses
{ "quote": {}, "firstPeriodChargeable": true, "billingDirection": "advance", "firstInvoiceDate": "2026-11-15" }
json
application/json

Integration readiness

GET
https://api.ledgerbee.com/api
/v1/checkout/readiness
x-api-key (header)
or
OAuth 2.0

Credential: a company's API key or OAuth token.

One object, a machine-readable state per tenant precondition — the "am I integrated?" preflight, replacing error-by-error discovery. Make this the first call of your integration.

Preconditions for a working checkout: the Subscription license, at least one published plan with a sellable item, and — for the card rail — an active Stripe Connect account. Hosted card windows additionally need your return origin on your embeddableOrigins allowlist. LedgerBee-hosted terms are NOT a precondition: generalTermsPublished is informational — when you host terms in LedgerBee they ride the quote/session and confirm records per-version acceptance; when you don't, you host your own terms and confirm records your acceptance assertion.

Customer groups are NOT a readiness item: they are per-request data. Discover them via GET /v1/customers/groups.

Required Scope

  • checkout

Integration readiness › Responses

CheckoutReadinessResponse
subscriptionLicense
​boolean · required

Whether you hold the Subscription license — without it nothing is checkoutable.

publishedPlans
​number · required

Number of published plans.

checkoutablePlans
​number · required

Number of published plans with a sellable item — checkoutable on this surface.

generalTermsPublished
​boolean · required

Informational, never a gate: whether published GENERAL terms exist in LedgerBee. When true, quote and session responses carry them and confirm records per-version acceptance evidence; when false, you host your own terms and confirm records your acceptance assertion.

​CheckoutReadinessStripeConnect · required
embeddableOrigins
​string[] · required

The configured embeddableOrigins allowlist — required for HOSTED card windows’ returnUrl.

GET/v1/checkout/readiness
curl https://api.ledgerbee.com/api/v1/checkout/readiness \ --header 'x-api-key: <api-key>'
Example Responses
{ "subscriptionLicense": true, "publishedPlans": 0, "checkoutablePlans": 0, "generalTermsPublished": true, "stripeConnect": { "connected": true, "status": "status", "settlementCurrency": "settlementCurrency", "allowCrossCurrencyCharges": true, "chargeableCurrencies": [ "string" ] }, "embeddableOrigins": [ "string" ] }
json
application/json

Mint a checkout session

POST
https://api.ledgerbee.com/api
/v1/checkout/session
x-api-key (header)
or
OAuth 2.0

Credential: a company's API key or OAuth token.

Mints the single-use session the rest of the flow runs against, PINNING what your buyer was shown: the plan version, the terms + disclosure versions, the resolved pricing and currency, quantities, VAT inputs and start date. Confirm re-runs the billing engine against those pinned inputs and refuses a drifted amount — you never bill a number the engine wouldn't produce, and a tenant republish affects new sessions only.

The buyer is plain request data — no tokens, no buyer verification. customerGroupId is REQUIRED (discover groups via GET /v1/customers/groups). Pass existingCustomerId for a returning buyer so they keep one customer record. Pass reference (your order/cart id) and every checkout.* webhook echoes it back. Pass discountCode to pin a code the quote priced; pinned.discountCode echoes it, and the card window and confirm judge it again before anything is created. With existingCustomerId the code is judged for that customer, so a code made for them is accepted; confirm judges it again once the buyer is proven to be that customer, and otherwise refuses with nothing created and the card hold released. Pass billingDirection to pin when the buyer pays; pinned.billingDirection and pinned.firstInvoiceDate echo it (the company's default when absent), and confirm creates the subscription in that direction.

The session expires after expiresInMinutes (default 30). An expired session answers 410 — re-mint and, if a card was already captured, carry its cardHandoffToken into the fresh session's confirm so the buyer never re-enters card details.

Required Scope

  • checkout

Mint a checkout session › Headers

x-api-idempotency-key
​string · maxLength: 255

Optional idempotency key for safely retrying mutating requests.

Mint a checkout session › Request Body

CheckoutSessionRequest
planVersionId
​string · uuid · required

The plan version to check out (from the catalogue).

planItemId
​string · uuid · required

The pricing-card item on that version.

​object · required

The buyer — plain request data; no tokens, no ceremony.

startDate
​string

Requested start date (YYYY-MM-DD). Defaults to today; never in the past.

currency
​string

Presentment currency (ISO 4217); must be in the card’s availableCurrencies.

​CheckoutQuantitySelection[]

Buyer-chosen quantities.

​CheckoutAddonSelection[]

Add-ons the buyer takes with the plan, each named by the catalogue item’s addons[].planId, with optional quantities. An add-on checkout sells bills at the plan’s period, on the same invoice as the plan. The same planId twice is refused with VALIDATION_FAILED. Absent or empty → the plan alone. The session pins the selection; confirm sells exactly what was pinned.

discountCode
​string · maxLength: 64

A discount code the buyer typed. Priced onto the first period (quote.discount states what it takes off, until when, and whether the first period is charged to the card) and attached to the subscription for its periods. An unknown, used-up or inapplicable code is refused with its DISCOUNT_* code; each request naming a code spends one use of the API key’s code-attempt budget (429 DISCOUNT_CHECK_RATE_LIMITED).

Example: WELCOME10
billingDirection
​string · enum

Whether the subscription bills each period in advance or in arrears. advance: the first period is invoiced on firstInvoiceDate, which is at confirm for a start date of today. arrears: nothing is invoiced at confirm, and the first invoice comes when the first period ends (firstInvoiceDate). Absent → the company’s default billing direction. The session pins the direction; confirm creates the subscription in it.

Enum values:
advance
arrears
Example: advance
expiresInMinutes
​number · min: 5 · max: 1440

Session TTL in minutes. Default 30.

reference
​string

Your own order/cart id (Stripe client_reference_id parity) — echoed on session reads, the confirm response and every checkout.* webhook payload.

language
​string · enum

Language for display texts, terms and the disclosure.

Enum values:
en
da

Mint a checkout session › Responses

CheckoutSessionResponse
sessionId
​string · required

The opaque session id — your handle for every later call.

expiresAt
​string · required

When the session expires (ISO 8601). Expired sessions answer 410.

reference
​string | null · required

Your reference, echoed.

quote
​object · required

The same first-period quote payload POST /v1/checkout/quote returns.

​object · required

What the session pinned — render exactly this.

firstPeriodChargeable
​boolean · required

False when the pinned first period nets to zero, when a discount code takes it below what a card can be charged, or when the session bills in arrears (save-only card window).

POST/v1/checkout/session
curl https://api.ledgerbee.com/api/v1/checkout/session \ --request POST \ --header 'Content-Type: application/json' \ --header 'x-api-key: <api-key>' \ --data '{ "planVersionId": "3f2b6f1e-8c4d-4e0b-9d5a-7a1c2e3f4b5d", "planItemId": "3f2b6f1e-8c4d-4e0b-9d5a-7a1c2e3f4b5d", "buyer": { "customerType": "BUSINESS", "name": "Acme ApS", "email": "buyer@example.com", "customerGroupId": "3f2b6f1e-8c4d-4e0b-9d5a-7a1c2e3f4b5d", "country": "DK", "vatNumber": "DK12345678", "address": "string", "postalCode": "string", "city": "string", "billingEmail": "billing@example.com", "existingCustomerId": "3f2b6f1e-8c4d-4e0b-9d5a-7a1c2e3f4b5d" }, "startDate": "string", "currency": "string", "quantities": [ { "priceId": "3f2b6f1e-8c4d-4e0b-9d5a-7a1c2e3f4b5d", "quantity": 0 } ], "addons": [ { "planId": "3f2b6f1e-8c4d-4e0b-9d5a-7a1c2e3f4b5d", "quantities": [] } ], "discountCode": "WELCOME10", "billingDirection": "advance", "expiresInMinutes": 5, "reference": "string", "language": "en" }'
Example Request Body
{ "planVersionId": "3f2b6f1e-8c4d-4e0b-9d5a-7a1c2e3f4b5d", "planItemId": "3f2b6f1e-8c4d-4e0b-9d5a-7a1c2e3f4b5d", "buyer": { "customerType": "BUSINESS", "name": "Acme ApS", "email": "buyer@example.com", "customerGroupId": "3f2b6f1e-8c4d-4e0b-9d5a-7a1c2e3f4b5d", "country": "DK", "vatNumber": "DK12345678", "address": "string", "postalCode": "string", "city": "string", "billingEmail": "billing@example.com", "existingCustomerId": "3f2b6f1e-8c4d-4e0b-9d5a-7a1c2e3f4b5d" }, "startDate": "string", "currency": "string", "quantities": [ { "priceId": "3f2b6f1e-8c4d-4e0b-9d5a-7a1c2e3f4b5d", "quantity": 0 } ], "addons": [ { "planId": "3f2b6f1e-8c4d-4e0b-9d5a-7a1c2e3f4b5d", "quantities": [] } ], "discountCode": "WELCOME10", "billingDirection": "advance", "expiresInMinutes": 5, "reference": "string", "language": "en" }
json
application/json
Example Responses
{ "sessionId": "sessionId", "expiresAt": "expiresAt", "reference": "reference", "quote": {}, "pinned": { "currency": "DKK", "netMajor": 0, "totalGrossMajor": 0, "startDate": "startDate", "disclosureVersion": "disclosureVersion", "disclosureText": "disclosureText", "acceptedTermsVersionIds": [ "string" ], "expiresInMinutes": 0, "addons": [ { "planId": "00000000-0000-0000-0000-000000000000", "quantities": [ { "priceId": "00000000-0000-0000-0000-000000000000", "quantity": 0 } ] } ], "discountCode": "discountCode", "billingDirection": "advance", "firstInvoiceDate": "2026-11-15" }, "firstPeriodChargeable": true }
json
application/json

Rehydrate a session

GET
https://api.ledgerbee.com/api
/v1/checkout/session/{id}
x-api-key (header)
or
OAuth 2.0

Credential: a company's API key or OAuth token.

PEEK a live session after a partner-side reload: the buyer payload, the pinned quote summary, your reference, and whether a card window was opened. 410 when expired or already consumed.

Required Scope

  • checkout

Rehydrate a session › path Parameters

id
​string · required

The opaque session id (64 hex chars).

Rehydrate a session › Responses

CheckoutSessionView
sessionId
​string · required

The opaque session id.

expiresAt
​string · required

When the session expires (ISO 8601).

reference
​string | null · required

Your reference, echoed.

planVersionId
​string · uuid · required

The pinned plan version.

planItemId
​string · uuid · required

The pinned pricing-card item.

buyer
​object · required

The buyer payload the session was minted with.

​CheckoutPinned · required
firstPeriodChargeable
​boolean · required

False when the pinned first period nets to zero, when a discount code takes it below what a card can be charged, or when the session bills in arrears.

cardWindowOpened
​boolean · required

Whether a card window has been opened on this session.

GET/v1/checkout/session/{id}
curl https://api.ledgerbee.com/api/v1/checkout/session/:id \ --header 'x-api-key: <api-key>'
Example Responses
{ "sessionId": "sessionId", "expiresAt": "expiresAt", "reference": "reference", "planVersionId": "00000000-0000-0000-0000-000000000000", "planItemId": "00000000-0000-0000-0000-000000000000", "buyer": {}, "pinned": { "currency": "DKK", "netMajor": 0, "totalGrossMajor": 0, "startDate": "startDate", "disclosureVersion": "disclosureVersion", "disclosureText": "disclosureText", "acceptedTermsVersionIds": [ "string" ], "expiresInMinutes": 0, "addons": [ { "planId": "00000000-0000-0000-0000-000000000000", "quantities": [ { "priceId": "00000000-0000-0000-0000-000000000000", "quantity": 0 } ] } ], "discountCode": "discountCode", "billingDirection": "advance", "firstInvoiceDate": "2026-11-15" }, "firstPeriodChargeable": true, "cardWindowOpened": true }
json
application/json

Release the card hold (edit-after-card)

POST
https://api.ledgerbee.com/api
/v1/checkout/session/{id}/card-release
x-api-key (header)
or
OAuth 2.0

Credential: a company's API key or OAuth token.

The edit-after-card loop's first step: when the buyer changes quantities, start date or VAT inputs AFTER the card step, confirm refuses the now-stale pinned amount — call this, then re-quote, re-mint and re-confirm.

SAVE_ONLY: the captured card SURVIVES (carry its cardHandoffToken into the fresh session's confirm — the buyer never re-enters card details; the first charge is sized at billing). RECAPTURE_REQUIRED: the card could not be preserved — discard it and open a fresh card window.

Required Scope

  • checkout

Release the card hold (edit-after-card) › path Parameters

id
​string · required

The opaque session id (64 hex chars).

Release the card hold (edit-after-card) › Headers

x-api-idempotency-key
​string · maxLength: 255

Optional idempotency key for safely retrying mutating requests.

Release the card hold (edit-after-card) › Responses

CheckoutCardReleaseResponse
status
​string · enum · required

SAVE_ONLY: the card survives — re-quote, re-mint and confirm; the first charge is sized at billing. RECAPTURE_REQUIRED: discard the card and open a fresh window.

Enum values:
SAVE_ONLY
RECAPTURE_REQUIRED
POST/v1/checkout/session/{id}/card-release
curl https://api.ledgerbee.com/api/v1/checkout/session/:id/card-release \ --request POST \ --header 'x-api-key: <api-key>'
Example Responses
{ "status": "SAVE_ONLY" }
json
application/json

Poll card status

GET
https://api.ledgerbee.com/api
/v1/checkout/session/{id}/card-status
x-api-key (header)
or
OAuth 2.0

Credential: a company's API key or OAuth token.

Poll after the buyer completes the card form: PENDING → keep polling, CARD_READY → confirm may proceed (the captured card's display details are included — show the buyer WHICH card will be charged), EXPIRED → the window lapsed, open a fresh one. The checkout.card_ready webhook is the push alternative; this poll stays authoritative.

Required Scope

  • checkout

Poll card status › path Parameters

id
​string · required

The opaque session id (64 hex chars).

Poll card status › Responses

CheckoutCardStatusResponse
status
​string · enum · required

PENDING: keep polling (or listen for checkout.card_ready). CARD_READY: confirm may proceed. EXPIRED: the window lapsed — open a fresh one.

Enum values:
PENDING
CARD_READY
EXPIRED
card
​object | null

The captured card (CARD_READY only).

GET/v1/checkout/session/{id}/card-status
curl https://api.ledgerbee.com/api/v1/checkout/session/:id/card-status \ --header 'x-api-key: <api-key>'
Example Responses
{ "status": "PENDING", "card": { "label": "Visa •••• 4242", "cardType": "cardType", "cardMask": "cardMask", "accountIdentifier": "accountIdentifier" } }
json
application/json

Open the card window

POST
https://api.ledgerbee.com/api
/v1/checkout/session/{id}/card-window
x-api-key (header)
or
OAuth 2.0

Credential: a company's API key or OAuth token.

Opens the Stripe card surface for the session — the ONLY place a card is ever entered (your systems never touch card data). The tenant's active Stripe Connect account is the card rail; there is no provider selection. Refused with CARD_PROVIDER_NOT_CONNECTED when Stripe isn't connected.

uiMode: 'embedded' (default) returns a clientSecret — mount Stripe's embedded Checkout on your page with Stripe.js (loadStripe(publishableKey, { stripeAccount })). uiMode: 'hosted' returns a redirectUrl to checkout.stripe.com; returnUrl is then REQUIRED and its origin must be on your embeddableOrigins allowlist. The flow is identical either way: the card lands asynchronously — poll card-status (or listen for checkout.card_ready), then confirm.

A zero first period still opens the window SAVE-ONLY: the card is stored for the first real charge and nothing is authorized ("no charge today").

Required Scope

  • checkout

Open the card window › path Parameters

id
​string · required

The opaque session id (64 hex chars).

Open the card window › Headers

x-api-idempotency-key
​string · maxLength: 255

Optional idempotency key for safely retrying mutating requests.

Open the card window › Request Body

CheckoutCardWindowRequest
uiMode
​string · enum

How the buyer meets Stripe's card form: 'embedded' (default) returns a client secret you mount on your page with Stripe.js; 'hosted' returns a redirect URL to checkout.stripe.com.

Enum values:
embedded
hosted
returnUrl
​string

Where Stripe sends the buyer back after a HOSTED window. REQUIRED for hosted (its origin must be on your embeddableOrigins allowlist); refused for embedded, which completes in-page.

Open the card window › Responses

CheckoutCardWindowResponse
mode
​string · enum · required

STRIPE_EMBEDDED → mount with clientSecret; REDIRECT → navigate the buyer to redirectUrl.

Enum values:
STRIPE_EMBEDDED
REDIRECT
handoffToken
​string · required

The card handoff token. It outlives the session: carry it into a fresh session’s confirm after an expiry and the buyer never re-enters card details.

expiresAt
​string · required

When the provider window expires (ISO 8601).

clientSecret
​string

Stripe embedded Checkout client secret (STRIPE_EMBEDDED only).

publishableKey
​string

Publishable key for Stripe.js (STRIPE_EMBEDDED only).

stripeAccountId
​string

The connected Stripe account id for Stripe.js (STRIPE_EMBEDDED only).

redirectUrl
​string

The hosted window URL to send the buyer to (REDIRECT only).

POST/v1/checkout/session/{id}/card-window
curl https://api.ledgerbee.com/api/v1/checkout/session/:id/card-window \ --request POST \ --header 'Content-Type: application/json' \ --header 'x-api-key: <api-key>' \ --data '{ "uiMode": "embedded", "returnUrl": "string" }'
Example Request Body
{ "uiMode": "embedded", "returnUrl": "string" }
json
application/json
Example Responses
{ "mode": "STRIPE_EMBEDDED", "clientSecret": "clientSecret", "publishableKey": "publishableKey", "stripeAccountId": "stripeAccountId", "redirectUrl": "redirectUrl", "handoffToken": "handoffToken", "expiresAt": "expiresAt" }
json
application/json

Open a card window for a live subscription

POST
https://api.ledgerbee.com/api
/v1/checkout/subscriptions/{id}/card-window
x-api-key (header)
or
OAuth 2.0

Credential: a company's API key or OAuth token.

The partner-UI path for adding or updating the card on an EXISTING subscription — same uiMode contract as the checkout card window, rendered to the buyer in your page. The window is save-only and binds to the buyer's stored payment profile; when the card lands (Stripe webhook), it becomes the card on file for that subscription and automatic charging turns on. Read the subscription until paymentMethodId is set. The buyer's emailed manage link remains the compliance floor and keeps working unchanged.

Adding a first card, or replacing a card from another provider, requires the subscription to allow Stripe: set allowedPaymentProviders: ["STRIPE"] on POST /v1/subscriptions or PATCH /v1/subscriptions/{id}. Without it the call answers 400 SUBSCRIPTION_MANAGE_PROVIDER_NOT_ALLOWED.

Required Scope

  • checkout

Open a card window for a live subscription › path Parameters

id
​string · uuid · required

The subscription id (any id in its version chain).

Open a card window for a live subscription › Headers

x-api-idempotency-key
​string · maxLength: 255

Optional idempotency key for safely retrying mutating requests.

Open a card window for a live subscription › Request Body

CheckoutCardWindowRequest
uiMode
​string · enum

How the buyer meets Stripe's card form: 'embedded' (default) returns a client secret you mount on your page with Stripe.js; 'hosted' returns a redirect URL to checkout.stripe.com.

Enum values:
embedded
hosted
returnUrl
​string

Where Stripe sends the buyer back after a HOSTED window. REQUIRED for hosted (its origin must be on your embeddableOrigins allowlist); refused for embedded, which completes in-page.

Open a card window for a live subscription › Responses

CheckoutCardWindowResponse
mode
​string · enum · required

STRIPE_EMBEDDED → mount with clientSecret; REDIRECT → navigate the buyer to redirectUrl.

Enum values:
STRIPE_EMBEDDED
REDIRECT
handoffToken
​string · required

The card handoff token. It outlives the session: carry it into a fresh session’s confirm after an expiry and the buyer never re-enters card details.

expiresAt
​string · required

When the provider window expires (ISO 8601).

clientSecret
​string

Stripe embedded Checkout client secret (STRIPE_EMBEDDED only).

publishableKey
​string

Publishable key for Stripe.js (STRIPE_EMBEDDED only).

stripeAccountId
​string

The connected Stripe account id for Stripe.js (STRIPE_EMBEDDED only).

redirectUrl
​string

The hosted window URL to send the buyer to (REDIRECT only).

POST/v1/checkout/subscriptions/{id}/card-window
curl https://api.ledgerbee.com/api/v1/checkout/subscriptions/:id/card-window \ --request POST \ --header 'Content-Type: application/json' \ --header 'x-api-key: <api-key>' \ --data '{ "uiMode": "embedded", "returnUrl": "string" }'
Example Request Body
{ "uiMode": "embedded", "returnUrl": "string" }
json
application/json
Example Responses
{ "mode": "STRIPE_EMBEDDED", "clientSecret": "clientSecret", "publishableKey": "publishableKey", "stripeAccountId": "stripeAccountId", "redirectUrl": "redirectUrl", "handoffToken": "handoffToken", "expiresAt": "expiresAt" }
json
application/json

BudgetsCompany