Documentation

Merchant checkout and payment links

Hosted checkout sessions, shareable payment links, and embeddable payment buttons.

The merchant services sub-module turns a banking account into a payment-acceptance surface. Three primitives compose every flow: a checkout session (a single payment in progress), a payment link (a shareable URL that creates sessions on demand), and a payment button (an HTML/iframe widget that drops into your site). All three settle into the merchant's bank account, with full ledger entries for each successful payment.

Checkout sessions

A session is the unit of one payment. It carries the amount, a customer reference, the payment provider being used, and a status that progresses through the lifecycle.

Lifecycle

pending → started → completed
              ↓ ↓
              fail  expire

Create

POST/banking/merchant/checkout/sessionsJWT
{
  "amount": 49.99,
  "currency": "USD",
  "customerEmail": "[email protected]",
  "customerName": "Alice Doe",
  "successUrl": "https://yourapp.com/order/success",
  "cancelUrl": "https://yourapp.com/order/cancel",
  "metadata": { "orderId": "ORD-1234" }
}

Response includes the full session plus a checkoutUrl — that's the URL you redirect the customer to.

Create from invoice

POST/banking/merchant/checkout/sessions/from-invoice/{invoiceId}JWT

For B2B flows where you've already issued an invoice. Pulls amount, customer, and reference from the invoice record and creates a matched session.

Lifecycle endpoints

POST/banking/merchant/checkout/sessions/{sessionId}/startJWT

Body: { paymentMethod: string }. Marks the session as started once the customer commits to paying. Used when your front end captures payment-method selection before submitting to the gateway.

POST/banking/merchant/checkout/sessions/{sessionId}/completeJWT
{
  "stripePaymentIntentId": "pi_...",
  "amount": 49.99,
  "paymentMethod": "card"
}

Confirms successful payment. The platform posts a journal entry crediting the merchant's bank account, fires merchant analytics events, and triggers any post-payment automation. Idempotent on stripePaymentIntentId.

POST/banking/merchant/checkout/sessions/{sessionId}/failJWT

Body: { reason: string }. Marks the session failed with the provider's decline reason.

POST/banking/merchant/checkout/sessions/{sessionId}/expireJWT

Marks the session expired after timeout (default 24 hours from creation).

Reads

GET/banking/merchant/checkout/sessionsJWT

Filter with status, sourceType (direct, link, invoice, button), page, pageSize.

GET/banking/merchant/checkout/sessions/{sessionId}JWT

Single session.

GET/banking/merchant/checkout/statsJWT

Aggregate stats: completion rate, total volume, average ticket size.

Hosted checkout pages

The platform ships a hosted checkout UI that works without you building any payment frontend:

GET/checkout/{sessionId}?orgId=ORGNo auth

Renders the hosted checkout HTML. Public route — the customer hits this directly in their browser. The orgId query parameter scopes the org. Card-data entry runs through the configured provider (typically Stripe Elements), so PCI exposure stays minimal on AppEngine's side.

GET/pay/{code}?orgId=ORGNo auth

Renders a payment-link landing page (see Payment Links below).

Both pages return raw HTML and post the resulting payment data back through the lifecycle endpoints.

Payment links

A payment link is a reusable shareable URL. Customers hit it, a session is created on the fly, and they're sent through hosted checkout.

Create

Payment links use the merchant dashboard endpoint cluster — see /banking/merchant/quick-link for fast creation:

POST/banking/merchant/quick-linkJWT
{
  "amount": 100.00,
  "description": "Consulting hour",
  "maxUses": null,
  "expiresAt": null
}

Each link gets a unique 8-character alphanumeric code. Public URL: https://your-domain/pay/{code}?orgId=ORG. Optionally generate a QR code for print or in-person use.

From invoice

The same merchant dashboard exposes link-from-invoice creation. The link inherits the invoice's amount and customer, and on payment completion the invoice is auto-marked paid.

Link features

FeatureBehavior
Fixed or variable amountIf amount is null, the customer enters their own.
Max usesAfter N completed payments, the link auto-expires.
ExpiryTime-bound; rejects sessions after expiresAt.
Custom fieldsCollect email, name, or arbitrary fields at checkout.
AnalyticsPer-link views, unique views, conversion rate, revenue.

Payment buttons

A button is a snippet of HTML/JS that drops into your own site. Useful for "Buy now" calls-to-action, donation widgets, and product cards.

Create

POST/banking/merchant/buttonsJWT
{
  "name": "Premium Plan",
  "amount": 29.99,
  "buttonType": "custom",
  "label": "Subscribe",
  "successUrl": "https://yoursite.com/thanks",
  "metadata": { "plan": "premium" }
}

Three button types:

TypeUse
productTied to a Storefront product. Price and metadata pulled from the product.
donationSuggested-amount or freeform donation widget.
customArbitrary one-time payment.

From product

POST/banking/merchant/buttons/from-product/{productId}JWT

Creates a button tied to a Storefront product. Price changes on the product propagate to the button.

Donation button

POST/banking/merchant/buttons/donationJWT
{
  "name": "Support our work",
  "description": "Choose any amount",
  "suggestedAmounts": [10, 25, 50, 100],
  "allowCustomAmount": true
}

Embed code

The create response (and the dedicated endpoint) returns three embed formats:

GET/banking/merchant/buttons/{buttonId}/embedJWT

?format=html|javascript|iframe.

The iframe form is the simplest:

<iframe
  src="https://appengine.appmint.io/banking/merchant/buttons/btn_abc?orgId=ORG"
  width="320"
  height="80"
  frameborder="0">
</iframe>

The HTML form gives you a styleable button. The JavaScript form mounts a button and opens checkout in a popup.

Lifecycle

POST/banking/merchant/buttons/{buttonId}/activateJWT
POST/banking/merchant/buttons/{buttonId}/deactivateJWT

Deactivated buttons return a "this button is not available" page on click.

DELETE/banking/merchant/buttons/{buttonId}JWT

Permanent removal.

Analytics

The platform tracks impressions, clicks, and conversions per button:

POST/banking/merchant/buttons/{buttonId}/impressionNo auth
POST/banking/merchant/buttons/{buttonId}/clickNo auth

Auto-fired by the embed code; you don't normally call them yourself.

GET/banking/merchant/buttons/statsJWT

Aggregate stats across all buttons in the org.

Merchant dashboard

GET/banking/merchant/dashboardJWT

Cross-cutting merchant view: counts and totals for links, sessions, buttons.

GET/banking/merchant/analyticsJWT

?startDate=2026-01-01&endDate=2026-04-30. Returns revenue, transactions, conversion, AOV for the period.

Settlement and payouts

Successful checkout sessions credit the merchant's business_checking account on settlement (typically T+2 for card payments through Stripe; faster for ACH/RTP-backed flows). The journal entry posts on completion, but the cash availability follows the underlying processor's settlement schedule.

Public vs authenticated routes

RouteAuthPurpose
POST /banking/merchant/checkout/sessionsJWTServer creates session
GET /checkout/:sessionIdPublicCustomer-facing hosted page
GET /pay/:codePublicPayment-link landing
POST /pay/:code/sessionPublicCustomer-initiated session creation from a link
POST /banking/merchant/buttons/:id/impressionPublicAnalytics ping from embed

Public endpoints take orgId as a query parameter rather than a header — so the iframe can be embedded without server-side header injection.