Merchant docs only
DGEN Payments API Reference
Store-scoped API docs for checkout orders, Stripe Auto-pay and subscriptions, products, payment links, wallets, admin-enabled store mailing, GCash Android automation, public checkout helpers, and signed outbound webhooks.
Endpoint groups
Jump to the part you need.
These docs intentionally exclude internal platform, cron, global, and provider-webhook endpoints. This page only lists endpoints a merchant integration or customer checkout can use.
Authentication API KEY
All /api/v1/* endpoints require Authorization: Bearer pdgen_live_.... Use Idempotency-Key on create endpoints when retrying from your backend.
curl -H 'Authorization: Bearer pdgen_live_xxx' https://payments.decentralizedgen.com/api/v1/store
Store API v1 - store API KEY
/api/v1/storeConfirm auth and read store status, provider toggles, payout currency, and owner profile.{ "id":"store_...", "status":"approved",
"providers": { "stripe_enabled":true, "gcash_enabled":true },
"owner": { "id":"usr_...", "email":"owner@example.com" } }Store API v1 - orders API KEY
/api/v1/ordersCreate a one-shot checkout order. Pass a product id or a custom amount. payment_method may be card, upi, or gcash and is added to checkout_url. Supports Idempotency-Key, metadata, return/cancel URLs, and custom expiry.{ "currency":"USD", "amount_minor":1999,
"payment_method":"upi",
"customer": { "email":"a@b.com", "name":"Alice", "phone":"+639..." },
"success_url":"https://merchant.example/paid",
"metadata": { "reference":"invoice_123" } }/api/v1/ordersList orders. Filters: status, customer_email, product_id, payment_link_id, provider, from, to, limit.{ "data":[{ "id":"ord_...", "status":"paid", "provider":"gcash" }], "limit":50 }/api/v1/orders/:idRead one order including customer, product, link, fees, metadata, GCash, UPI, Stripe, and refunds.{ "id":"ord_...", "provider":"gcash", "gcash": { "paid_minor":11248 } }/api/v1/orders/:id/cancelCancel a pending order.{ "ok": true }/api/v1/orders/:id/refundRefund all or part of a paid Stripe order. GCash is not refunded through this API because money goes to your own GCash account.{ "amount_minor":500, "reason":"duplicate" }Store API v1 - products API KEY
/api/v1/productsList products. Use ?archived=1 to include archived products.{ "data":[{ "id":"prd_...", "name":"VIP", "prices":[...] }] }/api/v1/productsCreate a product and auto-generate its permanent payment link.{ "name":"VIP", "base_currency":"USD", "base_amount_minor":1999 }/api/v1/products/:idRead one product. If its default link is missing, DGEN self-heals it.{ "id":"prd_...", "payment_link": { "checkout_url":"https://..." } }/api/v1/products/:idUpdate name, description, and price table.{ "name":"VIP v2" }/api/v1/products/:id/payment-linkGet or create the product's default permanent payment link.{ "id":"plk_...", "created":false, "checkout_url":"https://..." }Store API v1 - payment links API KEY
/api/v1/payment-linksCreate a product-bound or custom permanent link. Supports metadata and idempotency.{ "currency":"USD", "amount_minor":4900, "description":"Consult" }/api/v1/payment-linksList links. Filters: product_id, active, limit.{ "data":[{ "id":"plk_...", "checkout_url":"https://..." }] }/api/v1/payment-links/:idRead one link.{ "id":"plk_...", "active":true, "metadata":{} }/api/v1/payment-links/:idUpdate description, metadata, or active state.{ "active": false }/api/v1/payment-links/:idDelete link. Product auto-links self-heal on next product read.{ "ok": true }Store API v1 - user wallets API KEY
/api/v1/walletsCreate a per-customer wallet. Requires at least one of email, phone, or Discord id.{ "name":"Juan", "email":"juan@example.com", "phone":"+639..." }/api/v1/walletsList wallets for the store.{ "data":[{ "id":"uwl_...", "gcash_balance_minor":0 }] }/api/v1/wallets/:idRead one wallet.{ "id":"uwl_...", "topup_link_id":"plk_..." }/api/v1/wallets/:id/balanceRead Stripe and GCash wallet balances plus top-up checkout URL.{ "stripe": { "balance_minor":5000 }, "gcash": { "balance_minor":0 } }/api/v1/wallets/:id/ledgerNewest-first wallet ledger entries.{ "data":[{ "kind":"topup_gcash", "delta_minor":1999 }] }Store API v1 - Stripe auto-pay SCOPED API KEY
The store owner must approve the store, enable Stripe, accept the Auto-pay terms, and enable Auto-pay in DGEN first. Use a least-privilege scoped API key. Every mutation requires Idempotency-Key (8-120 printable ASCII characters); a same-key/same-input retry replays the result for 24 hours, while changed input returns HTTP 409. Payment data is collected directly by Stripe and DGEN never receives or stores PAN/CVC.
Supported payment methods
Card is the currently enabled and certified reusable Auto-pay method. Eligible Apple Pay, Google Pay, and Link experiences may be presented by Stripe as card-backed wallets depending on the customer's browser, device, country, and Stripe account configuration. Do not assume they will appear. GCash, UPI QR/UTR, crypto, BNPL, manual bank transfer, and other one-time methods are not Auto-pay methods. Bank debit and other mandate rails are not exposed by this API yet.
Required headers
Authorization: Bearer <store API key>
Content-Type: application/json
Idempotency-Key: <8-120 printable ASCII characters> # every POST, PATCH, DELETE
Auto-pay scopes
GET /autopay subscriptions:read
GET/POST/DELETE /return-origins subscriptions:read / subscriptions:write
GET/POST/PATCH/DELETE /subscription-plans plans:read / plans:write
GET/POST/PATCH/DELETE /subscription-links subscriptions:read / subscriptions:write
GET/POST/DELETE /billing-agreements agreements:read / agreements:write
POST /billing-agreements/:id/charges charges:write
GET /recurring-charges/:id subscriptions:read
GET/POST subscription resources subscriptions:read / subscriptions:write
Return URL allowlist
Register every external billing origin before using it as a setup return_url or subscription-link success_url/cancel_url. DGEN normalizes an HTTPS URL to its origin (scheme + hostname + optional non-default port), so paths, query strings, and fragments are not stored. Paymenter at billing.sereinhost.com must register https://billing.sereinhost.com. Registration expands only the allowed redirect origins; each submitted return URL is still checked against the store website, DGEN, or this explicit allowlist.
DGEN-managed subscription flow
1. GET /autopay and require accept_new_subscriptions=true.
2. POST /subscription-plans, or select an active existing plan.
3. POST /subscription-links with collection_mode=dgen_managed. For a billing platform, bind customer.external_reference and subscription_external_reference in this authenticated request, then redirect the customer to checkout_url.
4. Stripe Checkout collects the first payment, saves the reusable method, and creates the Stripe Billing subscription. DGEN creates the customer, agreement, and local subscription records.
5. Fulfil only from signed subscription.payment_succeeded/order.paid events or confirmed API state—not from a browser redirect.
The separate /billing-agreements/setup-sessions then /subscriptions flow remains available when a card must be linked before the plan is selected.
External-scheduler flow
Create a subscription link with collection_mode=external_scheduler and, when integrating a billing platform, bind the trusted customer.external_reference and subscription_external_reference during link creation. The public hosted form can submit customer email/name but can never choose either external reference. Its Checkout collects the first plan payment and saves the method with explicit off-session consent. After billing_agreement.active, correlate using data.customer_external_reference, then POST /billing-agreements/:id/charges once per later invoice using a unique Idempotency-Key and external_reference. HTTP 202 means accepted, not paid. Read GET /recurring-charges/:id and consume signed payment webhooks for the final result. Never run this mode and a DGEN-managed subscription for the same billing schedule.
Pagination and errors
List endpoints accept limit=1..100 and an opaque next_cursor returned by the previous page. Subscription lists also accept status and plan_id. Error bodies are JSON: { "error":"safe message", "code":"STABLE_CODE" }. Common statuses: 400 validation/idempotency header, 401 invalid key, 403 scope/store/Auto-pay restriction, 404 tenant-scoped resource not found, 409 state or idempotency conflict, 410 expired setup session, 402 failed off-session charge, 429 rate limit, and 5xx provider/service failure./api/v1/autopayRead store auto-pay and renewal-suspension state.{ "accept_new_subscriptions":true, "renewals_suspended":false }/api/v1/return-originsList additional allowlisted redirect origins. Scope: subscriptions:read.{ "data":[{ "origin":"https://billing.sereinhost.com", "label":"Paymenter" }] }/api/v1/return-originsAllowlist a normalized HTTPS origin for setup/link returns. Requires Idempotency-Key. Scope: subscriptions:write.{ "origin":"https://billing.sereinhost.com/account", "label":"Paymenter" }/api/v1/return-originsRemove an additional origin from future return-URL validation. Requires Idempotency-Key. Scope: subscriptions:write.{ "origin":"https://billing.sereinhost.com" }/api/v1/subscription-plansCreate an immutable recurring Stripe Product/Price mirror. Scope: plans:write.{ "name":"Pro", "currency":"USD", "amount_minor":1999, "interval":"month", "interval_count":1 }/api/v1/subscription-plansList plans. Scope: plans:read.{ "data":[{ "id":"spl_...", "name":"Pro" }] }/api/v1/subscription-plans/:idRead one tenant-scoped plan. Scope: plans:read.{ "id":"spl_...", "currency":"USD", "amount_minor":1999, "interval":"month", "active":true }/api/v1/subscription-plans/:idUpdate display fields or active state; price/currency/interval remain immutable. Scope: plans:write.{ "name":"Pro (new name)", "active":true }/api/v1/subscription-plans/:idArchive a plan without deleting subscription history. Scope: plans:write.{ "id":"spl_...", "archived":true }/api/v1/subscription-linksCreate a reusable hosted subscription link for DGEN-managed renewal or an external scheduler. Optionally bind trusted customer and subscription references here; the public form cannot set them. Scope: subscriptions:write.{ "plan_id":"spl_...", "collection_mode":"external_scheduler", "customer":{ "external_reference":"paymenter_user_42", "email":"a@b.com", "name":"Alice" }, "subscription_external_reference":"paymenter_service_84", "success_url":"https://merchant.example/billing/success", "max_uses":1 }/api/v1/subscription-linksList hosted subscription links and their checkout_url, mode, active state, and usage. Scope: subscriptions:read.{ "data":[{ "id":"slnk_...", "collection_mode":"dgen_managed", "checkout_url":"https://payments.decentralizedgen.com/subscribe/..." }] }/api/v1/subscription-links/:idUpdate description, usage limit, or active state. Plan and collection mode are immutable. Scope: subscriptions:write.{ "active":false }/api/v1/subscription-links/:idDisable future checkout sessions without affecting existing subscriptions or agreements. Scope: subscriptions:write.{ "id":"slnk_...", "active":false }/api/v1/billing-agreements/setup-sessionsCreate a single-use hosted card authorization URL. return_url must share the store website or DGEN origin. Scope: agreements:write.{ "customer":{ "external_reference":"customer_123", "email":"a@b.com", "name":"Alice" }, "return_url":"https://merchant.example/billing/complete" }/api/v1/billing-agreementsList safe payment-method metadata; Stripe identifiers are never returned. Scope: agreements:read.{ "data":[{ "id":"agr_...", "status":"active", "brand":"visa", "last4":"4242" }] }/api/v1/billing-agreements/:idRead one agreement and safe display metadata. Scope: agreements:read.{ "id":"agr_...", "status":"active", "method_type":"card", "display_name":"Visa ending 4242" }/api/v1/billing-agreements/:idRevoke future use. Active subscriptions must first be canceled or moved. Scope: agreements:write.{ "id":"agr_...", "status":"revoked" }/api/v1/subscriptionsCreate a DGEN-managed Stripe Billing subscription. Scope: subscriptions:write.{ "plan_id":"spl_...", "billing_agreement_id":"agr_...", "external_reference":"service_123", "quantity":1 }/api/v1/subscriptionsList customer subscriptions; filter by status or plan_id. Scope: subscriptions:read.{ "data":[{ "id":"sub_...", "status":"active" }] }/api/v1/subscriptions/:idRead one subscription with safe customer, plan, and payment display data. Scope: subscriptions:read.{ "id":"sub_...", "status":"active", "current_period_end":1788172800 }/api/v1/subscriptions/:id/cyclesList invoice/renewal cycles and retry state. Scope: subscriptions:read.{ "data":[{ "id":"cyc_...", "status":"paid", "attempt_count":1 }] }/api/v1/subscriptions/:id/eventsList the append-only subscription event timeline. Scope: subscriptions:read.{ "data":[{ "event_type":"subscription.active", "source":"stripe_webhook" }] }/api/v1/subscriptions/:id/pausePause collection for a managed subscription. Scope: subscriptions:write.{ "id":"sub_...", "status":"paused" }/api/v1/subscriptions/:id/resumeResume a paused subscription. Scope: subscriptions:write.{ "id":"sub_...", "status":"active" }/api/v1/subscriptions/:id/cancelCancel immediately or at period end.{ "when":"period_end" }/api/v1/subscriptions/:id/change-planMove a subscription to another immutable plan with explicit proration behavior.{ "plan_id":"spl_...", "proration_behavior":"create_prorations" }/api/v1/subscriptions/:id/retryRetry the latest eligible failed/open invoice. Scope: subscriptions:write.{ "subscription_id":"sub_...", "invoice_status":"paid", "accepted":true }/api/v1/subscriptions/:id/payment-method-sessionCreate a hosted card replacement session using a registered return_url. Scope: subscriptions:write.{ "return_url":"https://merchant.example/billing/complete" }/api/v1/billing-agreements/:id/chargesExternal-scheduler mode: request one confirmed off-session charge. Scope: charges:write.{ "amount_minor":1999, "currency":"USD", "external_reference":"invoice_123" }/api/v1/recurring-charges/:idRead asynchronous off-session charge status.{ "id":"rca_...", "status":"processing", "order_id":"ord_..." }Store API v1 - mailing API KEY
Send one email through the DGEN mail template after an administrator enables Mailing for the store. The store name is shown as the sender name; the actual From address remains the verified DGEN mailbox. Dashboard and API sends share two rolling 24-hour limits for that store: 10 pending or sent messages per normalized recipient and 100 total across all recipients. Failed sends release both quota slots.
Required headers
Authorization: Bearer <store API key>
Idempotency-Key: <required unique key>
Content-Type: application/json
Body parameters
to required valid email address
subject required string, 1–160 characters
html required string, maximum 32 KiB; server-allowlisted
css optional string, maximum 8 KiB; server-allowlisted
cURL request
curl -X POST 'https://payments.decentralizedgen.com/api/v1/mailing/send' \
-H 'Authorization: Bearer pdgen_live_xxx' \
-H 'Idempotency-Key: mailing-order-123' \
-H 'Content-Type: application/json' \
-d '{"to":"customer@example.com","subject":"Order update","html":"<p>Hello <strong>Alice</strong>.</p>","css":".store-mail-content strong { color: #61d83c; }"}'
Request body
{
"to": "customer@example.com",
"subject": "Order update",
"html": "<p>Hello <strong>Alice</strong>.</p>",
"css": ".store-mail-content strong { color: #61d83c; }"
}
HTTP 201
{
"message": {
"id": "mail_...",
"status": "sent",
"source": "api",
"to": "customer@example.com",
"subject": "Order update",
"sender": {
"name": "My Store",
"address": "payments@decentralizedgen.com"
},
"created_at": 1785500000,
"sent_at": 1785500001
},
"quota": {
"limit": 100,
"used": 1,
"remaining": 99,
"window_seconds": 86400,
"resets_at": 1785586400,
"recipient": {
"email": "customer@example.com",
"limit": 10,
"used": 1,
"remaining": 9,
"window_seconds": 86400,
"resets_at": 1785586400
}
}
}
Errors
403 MAILING_NOT_ENABLED An administrator has not enabled Mailing for this store.
409 Idempotency-Key was reused with conflicting input.
429 MAILING_QUOTA_EXCEEDED quota_scope is recipient after 10 messages to one address, or total after 100 messages from the store.
502 / 503 Mail provider or configuration failure./api/v1/mailing/sendSend one allowlisted HTML email with optional custom CSS inside the DGEN mail template. Exactly one recipient is accepted per request.{ "to":"customer@example.com",
"subject":"Order update",
"html":"<p>Hello <strong>Alice</strong>.</p>",
"css":".store-mail-content strong { color:#61d83c; }" }GCash Android app + notifications API KEY
The DGEN GCash Android app uses these endpoints after the merchant enters a Store API key and grants notification/background permissions.
/api/v1/gcash/heartbeatDevice heartbeat. Upserts the device row by store and hardware id.{ "hwid":"abc123", "phone_number":"+639...",
"device_model":"Pixel", "os_version":"Android",
"app_version":"1.0.0" }/api/v1/gcash/notificationsForward a receive notification. DGEN dedupes by dedupe_id, then matches exact amount or partial amount by phone.{ "full_notification":"You received PHP 499.00...",
"sender":"GCash", "from_number":"0917...", "amount":499,
"reference_no":"0041073634750", "dedupe_id":"gcash-ref-0041073634750",
"hwid":"abc123", "device_phone":"+639..." }/api/v1/gcash/store-infoCompatibility smoke test for the Android app. Redirects to /api/v1/store.301 redirect
/api/v1/gcash/notificationsRead recent inbound GCash notifications. Filter by match_type=exact|partial|unmatched.{ "data":[{ "id":"gcn_...", "match_type":"exact" }] }/api/v1/gcash/notifications/:idRead one notification row.{ "id":"gcn_...", "reference_no":"004107..." }Public checkout PUBLIC
/api/checkout/:tokenHydrate hosted checkout page state.{ "kind":"order", "status":"pending", "available_providers":{...} }/api/checkout/:token/quote?currency=EURCurrency quote for checkout currency selection.{ "currency":"EUR", "amount_minor":1830, "fx_rate":0.929 }/api/checkout/:token/customerSubmit customer details for a one-shot order or permanent link visit.{ "email":"a@b.com", "name":"Alice", "phone":"+639..." }/api/checkout/:token/select-providerChoose stripe, crypto, gcash, or upi where available.{ "provider":"gcash" }/api/checkout/:token/intentCreate/reuse Stripe PaymentIntent.{ "client_secret":"pi_..._secret_..." }/api/checkout/:token/statusPoll paid/partial/failed status.{ "status":"partial", "remaining_minor":5000 }/api/checkout/:token/gcash-phoneSave customer GCash phone for SMS matching.{ "phone":"+639..." }/api/checkout/:token/gcash-reconcileCheckout-side reconcile helper for GCash pending/partial orders.{ "ok": true }/api/checkout/:token/upi-utrSubmit UPI UTR/reference for checkout-side tracking.{ "utr":"123456789012" }/api/checkout/:token/wallet-payPay from a customer wallet balance where available.{ "wallet_id":"uwl_...", "balance":"gcash" }/api/checkout/:token/reset-customerClear customer details and provider.{ "ok": true }/api/checkout/:token/reset-providerClear selected provider only.{ "ok": true }/api/checkout/:token/failMark expired checkout as failed after countdown.{ "ok": true, "status":"failed" }Payment-link URL params PUBLIC
Append these to any /pay/<token> URL returned by the Store API. In an iframe, DGEN opens UPI apps through a top-level navigation and emits checkout.open_external to the verified parent origin as a fallback. Sandboxed iframes must allow user-activated top navigation and custom protocols.
Direct payment method
?method=card
?method=upi
?method=gcash
Customer and metadata
?email=alice@example.com&name=Alice&phone=%2B639...
&reference=invoice_123
&metadata[paymenter_invoice_id]=123
&autosubmit=0
Overlay iframe
<iframe
src="https://payments.decentralizedgen.com/pay/<token>?embed=1&method=upi&return_origin=https%3A%2F%2Fmerchant.example"
allow="payment"
sandbox="allow-scripts allow-forms allow-same-origin allow-top-navigation-by-user-activation allow-top-navigation-to-custom-protocols">
</iframe>
window.addEventListener("message", (event) => {
if (event.origin !== "https://payments.decentralizedgen.com") return;
const message = event.data;
if (message?.source !== "dgen-payments") return;
if (message.type === "checkout.open_external" && /^(upi|gpay|phonepe|paytmmp|intent):/i.test(message.url)) {
window.location.assign(message.url);
}
});Outbound webhook payloads SIG
Configured merchant webhook URLs receive X-DGEN-Signature: t=<unix>,v1=<hmac>.
order.paidStripe, GCash, UPI, or wallet order captured. Includes metadata and top-level reference.{ "event":"order.paid", "data":{ "order_id":"ord_...", "reference":"invoice_123" } }order.refundedRefund total increased on a Stripe order.{ "event":"order.refunded", "data":{ "order_id":"ord_...", "refunded_delta_minor":500 } }order.failedCheckout expired or failed.{ "event":"order.failed", "data":{ "order_id":"ord_...", "reason":"expired" } }payout.sentA merchant payout request was marked sent.{ "event":"payout.sent", "data":{ "payout_id":"pay_...", "amount_minor":50000 } }billing_agreement.active | billing_agreement.revokedA reusable payment agreement became usable or was revoked. customer_external_reference echoes the trusted merchant reference for correlation.{ "event":"billing_agreement.active", "ts":1785500000, "data":{ "billing_agreement_id":"agr_...", "customer_id":"cus_...", "customer_external_reference":"paymenter_user_42" } }subscription.created | active | updated | paused | resumed | canceling | canceledManaged subscription lifecycle changed. Treat delivery as at-least-once and fetch current state when ordering matters.{ "event":"subscription.active", "ts":1785500000, "data":{ "subscription_id":"sub_...", "status":"active" } }subscription.payment_processing | succeeded | failed | action_requiredA managed subscription invoice/payment changed state. Provision only from succeeded/current confirmed state.{ "event":"subscription.payment_succeeded", "ts":1785500000, "data":{ "subscription_id":"sub_...", "order_id":"ord_...", "cycle_id":"cyc_..." } }