Main Backend Public Endpoints
Buyer-facing and provider-facing endpoints used by hosted checkout, portal, and webhook flows.
Main Backend Public Endpoints
Base URL: https://<your-main-backend-host>/api/v1 — your deployment sets the host via MAIN_BACKEND_DOMAIN. Self-hosted examples often use webhook.yourcompany.com or webhook.example.com; hosted production uses https://webhook.payment-gateway.app — Hostnames & DNS conventions, Self-Hosted Installation.
The Main Backend handles buyer-facing runtime operations: serving checkout sessions, processing transaction submissions, powering the customer portal, validating VAT IDs, and receiving incoming provider webhooks.
[!IMPORTANT] This is not the primary merchant integration surface. Merchants should create and manage checkouts through the Admin API using Organization API keys or System API keys where appropriate. The endpoints below are mainly consumed by the hosted checkout UI, portal UI, and payment-provider infrastructure.
Checkouts
Get Checkout Session
GET /api/v1/checkouts/:idRetrieves a checkout session by its public ID. Used by the Main Frontend to render the payment page.
When the response includes checkoutSettings.vatIdValidation, the value is the effective runtime mode exposed to checkout, not just the raw merchant preference. If checkout is configured for vies but organization tax settings do not currently allow VIES-backed tax handling, the Main Backend downgrades the session response to format so buyer-facing validation stays aligned with backend tax behavior.
Authentication: No API key/JWT required. License enforcement applies (requests are denied when license state is BLOCKED or NOT_ACTIVATED).
Browser access (CORS): This endpoint enforces an Origin allow-list derived from the Site/Organization frontend domains plus MPG_MAIN_FRONTEND_DOMAIN. Requests without a valid Origin (or Referer) will be rejected with 403.
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
id | string | Public checkout session ID |
Response 200:
{
"id": "abc123",
"currency": "EUR",
"status": "pending",
"lineItems": [
{
"name": "Professional Plan",
"quantity": 1,
"unitAmount": 4900
}
],
"providers": ["stripe"],
"branding": {
"logo": "https://...",
"primaryColor": "#3b82f6"
},
"expiresAt": "2026-03-08T14:00:00Z"
}Preview Checkout Tax
POST /api/v1/checkouts/:id/tax-previewReturns backend-calculated checkout totals for the current billing details before the buyer submits payment. The response is used by the hosted checkout UI to display net, tax, gross, and tax breakdown values while preserving the final calculation for transaction creation.
The endpoint uses organization tax settings, effective-dated tax rates, tax rules, gross/net price mode, rounding, shipping destination overrides for goods/shipping lines, and VIES-backed buyer type only when the effective checkout VAT validation mode allows VIES.
Request Body:
{
"billingAddress": {
"country": "DE",
"postcode": "10115",
"vatId": "DE123456789"
}
}Response 200:
{
"taxIncluded": true,
"totalNet": 4118,
"totalTax": 782,
"totalGross": 4900,
"taxBreakdown": [
{
"taxRate": 19,
"taxRateCode": "DE_STANDARD",
"taxableBase": 4118,
"taxAmount": 782
}
]
}Checkout Handoff
Cross-domain checkout flows can store provider and billing selections behind a short-lived opaque token before the buyer completes payment on the hosted checkout domain.
Create Handoff Token
POST /api/v1/checkouts/:id/handoff
Content-Type: application/jsonRequest Body:
{
"providerId": "507f1f77bcf86cd799439011",
"billingAddress": {
"name": "Jane Smith",
"email": "jane@example.com",
"line1": "123 Main St",
"city": "Berlin",
"postalCode": "10115",
"country": "DE"
}
}billingAddress is optional. The :id path parameter is the checkout session public ID.
Response 200:
{
"handoffToken": "opaque_token_value",
"expiresInSeconds": 600
}Consume Handoff Token
POST /api/v1/checkouts/:id/handoff/:token/consumeReturns the stored provider and billing payload and deletes the token (single use). The :id path parameter is the checkout session public ID; :token is the value from Create Handoff Token.
Response 200:
{
"providerId": "507f1f77bcf86cd799439011",
"billingAddress": {
"name": "Jane Smith",
"email": "jane@example.com",
"line1": "123 Main St",
"city": "Berlin",
"postalCode": "10115",
"country": "DE"
},
"createdAt": "2026-03-08T14:00:00Z"
}Transactions
Create Transaction
POST /api/v1/transactions/createInitiates a transaction for a checkout session. Called by the Main Frontend when the customer submits payment.
Authentication: No API key/JWT required. License enforcement applies (requests are denied when license state is BLOCKED or NOT_ACTIVATED).
Request Body:
{
"sessionPublicId": "sess_pub_abc123xyz",
"providerId": "507f1f77bcf86cd799439011",
"billingAddress": {
"name": "Jane Smith",
"email": "jane@example.com",
"line1": "123 Main St",
"city": "Berlin",
"postalCode": "10115",
"country": "DE"
}
}Response 200:
{
"transactionId": "67c8e2f7d6ef0dc8a3fa2011",
"status": 0
}Get Transaction Status
GET /api/v1/transactions/:id/statusPolls transaction status. Used by the success/return page to confirm payment outcome.
Response 200:
{
"status": 1,
"externalReference": "order_12345",
"amount": 4900,
"currency": "EUR",
"returnUrl": "https://yourapp.com/success?txId={transactionId}",
"createdAt": "2026-03-08T14:00:00Z"
}status is a numeric transaction status code (same integer codes used elsewhere in the gateway). externalReference and returnUrl are omitted when empty.
Cancel Transaction
POST /api/v1/transactions/:id/cancelCancels a pending transaction (before provider capture).
Mark Transaction as Pending
POST /api/v1/transactions/:id/mark-pendingTransitions a transaction to pending_provider state. Used for asynchronous payment flows (GoCardless, Wire Transfer).
VAT Validation
Validate VAT ID
POST /api/v1/vat/validateValidates a VAT ID via the EU VIES system. No authentication required.
Hosted checkout only calls this endpoint when the effective checkoutSettings.vatIdValidation mode resolves to vies for the current session.
Request Body:
{
"vatId": "DE123456789"
}Response 200:
{
"valid": true,
"companyName": "Example GmbH",
"address": "Musterstraße 1, 10115 Berlin"
}Check EU Country
GET /api/v1/vat/eu-country/:codeReturns whether a country code is an EU member state.
Customer Portal
The portal API allows buyers to self-serve invoice and subscription management. All portal endpoints except auth endpoints require a valid portal session token.
Request OTP
POST /api/v1/portal/auth/request-otpSends a one-time password to the customer's email address.
Request Body:
{
"email": "jane@example.com"
}Verify OTP
POST /api/v1/portal/auth/verify-otpExchanges an OTP for a portal session token.
Request Body:
{
"email": "jane@example.com",
"code": "123456"
}Response 200:
{
"token": "portal_session_token",
"expiresAt": "2026-03-08T16:00:00Z"
}Upon OTP verification, the backend issues a signed portal session token (opaque bearer token). It is not a JWT; treat it as an opaque credential and send it as:
Authorization: Bearer <portal_session_token>Exchange Magic Link
POST /api/v1/portal/auth/magic-linkExchanges a one-time magic-link token for the same portal session response as OTP verification. Magic-link tokens are single-use; replayed, expired, or malformed tokens return an authentication error.
Request Body:
{
"token": "portal_magic_link_token"
}Refresh Portal Session
POST /api/v1/portal/auth/refreshRotates the HTTP-only portal refresh cookie and returns a fresh portal session token. The frontend calls this endpoint when a portal API request receives 401 Unauthorized.
Logout Portal Session
POST /api/v1/portal/auth/logoutClears the portal refresh cookie. The frontend also removes the in-memory portal bearer token.
Get Portal Session
GET /api/v1/portal/sessionReturns authenticated portal metadata for UI bootstrapping.
Response 200:
{
"email": "jane@example.com",
"hasSubscriptions": true
}All subsequent portal requests include:
Authorization: Bearer portal_session_tokenList Documents
GET /api/v1/portal/documentsReturns portal-visible billing documents for the authenticated customer: standard invoices in draft or issued state and issued credit notes. Pro forma invoices are excluded from the document list.
Download Document PDF
GET /api/v1/portal/documents/:id/pdf?type=invoice
GET /api/v1/portal/documents/:id/pdf?type=credit-noteReturns the invoice or credit-note PDF as application/pdf. If type is omitted, the backend treats the document as an invoice.
Download E-Invoice (XML)
GET /api/v1/portal/documents/:id/einvoice?format=xrechnungReturns the requested e-invoice XML when that format is enabled for both organization eInvoice generation and portal downloads. Supported format values are xrechnung, peppol, and zugferd; peppol returns Peppol BIS 3.0 XML generated against Peppol BIS Billing 3.0.20-hotfix, and zugferd returns standalone Factur-X/ZUGFeRD CII XML. Readiness failures return 422 EINVOICE_READINESS_FAILED. Standard invoice PDFs are downloaded through /api/v1/portal/documents/:id/pdf.
Peppol portal downloads use the seller and buyer Peppol routing addresses stored on the invoice snapshot. XRechnung and ZUGFeRD do not require Peppol routing addresses. If a Peppol snapshot is missing or invalid, fix the organization/client setup for future documents and use the admin invoice correction workflow for already issued documents. Credit notes are available through the portal as PDF documents; the portal e-invoice endpoint is invoice-only.
List Subscriptions
GET /api/v1/portal/subscriptionsReturns visible recurring subscriptions for the authenticated buyer.
Response 200:
{
"subscriptions": [
{
"id": "67c8e2f7d6ef0dc8a3fa2011",
"name": "Annual software renewal",
"status": "cancel_requested",
"cadence": "Every 1 year",
"currency": "EUR",
"nextChargeDate": null,
"effectiveAt": "2026-09-01T00:00:00Z",
"estimatedNextAmount": 0,
"upcomingChargesCount": 0
}
],
"total": 1,
"page": 1,
"limit": 20
}Get Subscription Upcoming Charges
GET /api/v1/portal/subscriptions/:id/upcoming?count=6Returns the current recurring state, the next scheduled charge if billing is still active, and upcoming charge estimates. For scheduled or finalized cancellations, the response also includes the stored cancellation reason and requested timestamp when present.
Response 200:
{
"subscriptionId": "67c8e2f7d6ef0dc8a3fa2011",
"name": "Annual software renewal",
"status": "active",
"cadence": "Every 1 year",
"currency": "EUR",
"nextChargeDate": "2026-09-01T00:00:00Z",
"effectiveAt": null,
"cancellationReason": null,
"cancellationRequestedAt": null,
"upcoming": [
{
"id": "67c8e2f7d6ef0dc8a3fa2011-1",
"scheduledDate": "2026-09-01T00:00:00Z",
"dueDate": "2026-09-15T00:00:00Z",
"currency": "EUR",
"baseAmount": 149000,
"usageAmount": 0,
"taxEstimate": 0,
"estimatedTotal": 149000,
"proformaAvailable": true,
"proformaPreviewId": "next",
"proformaPreviewLabel": "Proforma preview"
}
]
}Download Subscription Proforma Preview PDF
GET /api/v1/portal/subscriptions/:id/upcoming/:upcomingId/proforma/pdfDownloads the optional PDF preview for the first upcoming recurring charge when proforma previews are enabled.
Cancel Subscription
POST /api/v1/portal/subscriptions/:id/cancelAllows a customer to cancel a recurring schedule. The operation is idempotent and uses future-cycle semantics when the schedule still has a next run date.
Request Body:
{
"reason": "Switching to annual billing"
}reason is optional. When provided, the backend trims the value, caps it at 500 characters, and stores it on the recurring schedule for operator records. Repeated cancellation calls keep the existing cancellation state instead of creating a second mutation.
Response 200:
{
"subscriptionId": "67c8e2f7d6ef0dc8a3fa2011",
"status": "cancel_requested",
"alreadyCancelled": false,
"effectiveAt": "2026-09-01T00:00:00Z",
"cancellationReason": "Switching to annual billing",
"cancellationRequestedAt": "2026-06-09T12:00:00Z",
"message": "Subscription cancellation scheduled for future cycles"
}Billing Requests (GoCardless)
Create Billing Request
POST /api/v1/billing-requests/createInitiates a GoCardless billing request mandate. Called during the direct debit checkout flow.
Webhooks (Inbound)
Registered on the Main Backend HTTP root (not under /api/v1):
POST /hooks/:type/:providerIdReceives inbound webhook events from payment providers. Not called by your code — configure the full URL (including your Main API host) in the provider dashboard.
type | Provider |
|---|---|
stripe | Stripe payment events |
mollie | Mollie payment events |
gocardless | GoCardless mandate and payment events |
paypal | PayPal order and payment events |
See Webhooks & IPN for event types and payload schemas.