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
/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
/banking/merchant/checkout/sessions/from-invoice/{invoiceId}JWTFor 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
/banking/merchant/checkout/sessions/{sessionId}/startJWTBody: { 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.
/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.
/banking/merchant/checkout/sessions/{sessionId}/failJWTBody: { reason: string }. Marks the session failed with the provider's decline reason.
/banking/merchant/checkout/sessions/{sessionId}/expireJWTMarks the session expired after timeout (default 24 hours from creation).
Reads
/banking/merchant/checkout/sessionsJWTFilter with status, sourceType (direct, link, invoice, button), page, pageSize.
/banking/merchant/checkout/sessions/{sessionId}JWTSingle session.
/banking/merchant/checkout/statsJWTAggregate 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:
/checkout/{sessionId}?orgId=ORGNo authRenders 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.
/pay/{code}?orgId=ORGNo authRenders 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:
/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
| Feature | Behavior |
|---|---|
| Fixed or variable amount | If amount is null, the customer enters their own. |
| Max uses | After N completed payments, the link auto-expires. |
| Expiry | Time-bound; rejects sessions after expiresAt. |
| Custom fields | Collect email, name, or arbitrary fields at checkout. |
| Analytics | Per-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
/banking/merchant/buttonsJWT{
"name": "Premium Plan",
"amount": 29.99,
"buttonType": "custom",
"label": "Subscribe",
"successUrl": "https://yoursite.com/thanks",
"metadata": { "plan": "premium" }
}
Three button types:
| Type | Use |
|---|---|
product | Tied to a Storefront product. Price and metadata pulled from the product. |
donation | Suggested-amount or freeform donation widget. |
custom | Arbitrary one-time payment. |
From product
/banking/merchant/buttons/from-product/{productId}JWTCreates a button tied to a Storefront product. Price changes on the product propagate to the button.
Donation button
/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:
/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
/banking/merchant/buttons/{buttonId}/activateJWT/banking/merchant/buttons/{buttonId}/deactivateJWTDeactivated buttons return a "this button is not available" page on click.
/banking/merchant/buttons/{buttonId}JWTPermanent removal.
Analytics
The platform tracks impressions, clicks, and conversions per button:
/banking/merchant/buttons/{buttonId}/impressionNo auth/banking/merchant/buttons/{buttonId}/clickNo authAuto-fired by the embed code; you don't normally call them yourself.
/banking/merchant/buttons/statsJWTAggregate stats across all buttons in the org.
Merchant dashboard
/banking/merchant/dashboardJWTCross-cutting merchant view: counts and totals for links, sessions, buttons.
/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
| Route | Auth | Purpose |
|---|---|---|
POST /banking/merchant/checkout/sessions | JWT | Server creates session |
GET /checkout/:sessionId | Public | Customer-facing hosted page |
GET /pay/:code | Public | Payment-link landing |
POST /pay/:code/session | Public | Customer-initiated session creation from a link |
POST /banking/merchant/buttons/:id/impression | Public | Analytics 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.