Shopify Payments App Integration
Piaxis can act as the payment provider at a Shopify store’s checkout: buyers pay with mobile money (MTN or Airtel in v1) and the money lands either directly in the merchant’s Piaxis store settlement or inside a Piaxis escrow — the business chooses at install time.
Status
The integration ships disabled by default. It activates only when both are true:
The platform operator has set
SHOPIFY_INTEGRATION_ENABLEDand the Shopify app credentials (see Configuration).The merchant’s store holds the
shopify_paymentsentitlement, granted by a Piaxis administrator (plan or override). This key is deliberately not part of the free baseline.
Until Shopify Partner review of the Piaxis Payments App completes, treat every environment as sandbox.
How It Works
Shopify checkout
│ payment session webhook (HMAC-verified)
▼
Piaxis records the session and answers with a hosted payment URL
│ buyer is redirected
▼
gopiaxis.com/pay/shopify/{session} ← buyer picks MTN/Airtel, enters phone
│ mobile-money push on existing Piaxis rails
▼
money is FINAL (settled directly, or held in escrow)
│ paymentSessionResolve via Shopify GraphQL
▼
Shopify completes the order; buyer returns to the shop
Key guarantees:
A Shopify order is never confirmed before the buyer’s money is final.
Webhook replays are idempotent by Shopify session id — money can never be collected twice for one session.
If the buyer closes the page mid-payment, a reconciliation task finishes the session (resolve or reject) on its own.
Refunds can never exceed what was actually collected; an over-amount refund session is rejected with a typed reason.
Connecting a Shop (merchant flow)
The store owner starts the install from Piaxis (session-authenticated):
POST /api/platforms/shopify/connect
Content-Type: application/json
{
"store_id": "<piaxis store uuid>",
"shop_domain": "my-shop.myshopify.com",
"payment_mode": "direct"
}
payment_mode—directsettles collected money straight to the store’s settlement balance;escrowholds each payment in a Piaxis escrow released through the normal escrow lifecycle (buyer protection). A business may run both models by connecting different shops.The response contains
install_url: send the merchant’s browser there. It is Shopify’s own authorize page requesting the minimum Payments App scopes (write_payment_gateways,write_payment_sessions).Shopify redirects back to
GET /api/platforms/shopify/oauth/callback; Piaxis verifies the signature and state, exchanges the code, and stores the shop’s offline token encrypted at rest. The plaintext token never reaches a client.
To disconnect:
DELETE /api/platforms/shopify/connect/{shop_domain}
The token reference is dropped immediately; further payment sessions from
that shop are refused. Uninstalling the app from the Shopify side has the
same effect via the app/uninstalled webhook.
Hosted Payment Page
Buyers land on https://gopiaxis.com/pay/shopify/{session_id}. The page is
guest-safe: no Piaxis account, KYC, or PIN prompt — the mobile-money PIN is
only ever entered on the buyer’s own phone. It offers exactly the methods the
store’s market configuration enables, and it polls session status so the
order confirms without any buyer action after approving on the phone.
The page consumes these public endpoints (the unguessable session UUID from the Shopify redirect is the capability):
GET /api/platforms/shopify/sessions/{session_id}— status, amount, currency, available methods.POST /api/platforms/shopify/sessions/{session_id}/pay— body{"phone_number": "...", "method": "mtn" | "airtel"}. Single-flight: while a push is pending the endpoint answers409.POST /api/platforms/shopify/sessions/{session_id}/cancel— allowed only before money moves; rejects the Shopify session as customer-cancelled.
Webhooks (Shopify-facing)
These endpoints exist for Shopify itself, not for merchant integrations.
Every call is verified against the raw request body with the app secret
(X-Shopify-Hmac-Sha256) before any processing:
POST /api/platforms/shopify/webhooks/payment-sessionPOST /api/platforms/shopify/webhooks/refund-sessionPOST /api/platforms/shopify/webhooks/capture-session(v1 declares automatic capture)POST /api/platforms/shopify/webhooks/void-session(cancels sessions whose money is not yet final; settled money requires a refund)POST /api/platforms/shopify/webhooks/events— lifecycle and the mandatory GDPR topics (customers/data_request,customers/redact,shop/redact), all recorded replay-safe.
Configuration
Platform-operator environment variables:
Variable |
Purpose |
|---|---|
|
Master switch. Everything answers |
|
The Shopify Partner app credentials. The secret verifies webhook and OAuth signatures — rotating it invalidates in-flight installs. |
|
|
|
Already required by the platform; also encrypts shop offline tokens. |
|
Sandbox-only JSON map of token references for shops connected outside the OAuth flow. Production connections use encrypted refs instead. |
Administrator steps (one-time, via the admin console → Store Entitlements):
Create the
shopify_paymentsfeature (default stateplan_requiredordisabled).Enable it for the market (Market availability row, e.g.
UG/*).Grant it to pilot stores via a plan or per-store override.
Existing Integrations Are Unaffected
This surface is additive. No existing Payment API route, SDK method, webhook payload, or escrow behavior changed; the regression suites for the external API and escrow run against every release of this integration.