▲ Live demo — a single-product storefront with one-time checkout via Antom CKP Embedded.
Accept global payments via Antom Checkout Page (Embedded), powered by Next.js 14 App Router.
⚠️ For demonstration purposes only. This template is for demonstration purposes only, is not production-ready, and is provided "as-is" without warranty. To the maximum extent permitted under applicable laws, Antom assumes no liability for any losses arising from its use or deployment. By using this template, you are acknowledging and agreeing to this. See LEGAL.md and LICENSE for trademark, AML/KYC, and warranty notices.
- 100+ global payment methods via a single integration
- RSA2 (SHA256withRSA) request signing — no third-party SDK dependency
- CKP Embedded mode — checkout stays in your page
- One-click deploy to Vercel with pre-configured environment variables
- Webhook signature verification + idempotent processing
Browser ─▶ Next.js App Router (server) ─▶ Antom Gateway (Asia)
▲ │
└── CKP Embedded SDK (js.antom.com) ◀────────┘
Webhook: Antom Gateway ─▶ POST /api/webhooks/antom ─▶ verify + update
| Variable | Required | Exposed to Client | Description |
|---|---|---|---|
ANTOM_CLIENT_ID |
✅ | No | Merchant identifier from Antom Dashboard → Developer → Integration Settings |
ANTOM_PRIVATE_KEY |
✅ | No | RSA2048 private key, single-line base64, no PEM headers |
ANTOM_PUBLIC_KEY |
✅ | No | Antom platform public key for webhook verification |
ANTOM_GATEWAY_URL |
✅ | No | https://open-sea-global.alipay.com (Asia) |
NEXT_PUBLIC_ANTOM_ENV |
✅ | Yes | sandbox or prod |
NEXT_PUBLIC_SITE_URL |
✅ | Yes | Your deployment origin |
Must be a single-line base64 string, no PEM headers. Convert with:
awk 'NF{printf "%s",$0}' priv.pem | sed 's/-----[^-]*-----//g'| Region | URL |
|---|---|
| Asia (default) | https://open-sea-global.alipay.com |
| Europe | https://open-eu-global.alipay.com |
| Americas | https://open-us-global.alipay.com |
| Global | https://open-global.alipay.com |
# 1. Install
pnpm install
# 2. Configure env
cp .env.example .env.local
# 3. Generate RSA key pair
openssl genpkey -algorithm RSA -out priv.pem -pkeyopt rsa_keygen_bits:2048
openssl rsa -in priv.pem -pubout -out pub.pem
# 4. Convert private key to single-line, paste into ANTOM_PRIVATE_KEY
awk 'NF{printf "%s",$0}' priv.pem | sed 's/-----[^-]*-----//g'
# 5. Upload pub.pem to Antom Dashboard; download Antom platform public key
# → paste into ANTOM_PUBLIC_KEY
# 6. Run
pnpm dev # http://localhost:3000- User clicks Pay → frontend POSTs to
/api/create-payment-session - Server signs request with RSA2, calls Antom
createPaymentSession - Returns
paymentSessionDatato frontend - Frontend loads
ams-checkout.js→ mounts CKP Embedded - User completes payment inside iframe
- SDK fires
SDK_PAYMENT_*events (UI only, never trust for fulfillment) - Browser redirects to
/result→ server callsinquiryPayment - In parallel: Antom pushes webhook → server verifies RSA → updates order
antom-nextjs-template/
├── app/
│ ├── page.tsx # Inline checkout (single product)
│ ├── checkout-embedded/page.tsx # CKP container
│ ├── result/page.tsx # Inquiry + status
│ └── api/
│ ├── create-payment-session/ # POST: create session
│ ├── inquiry-payment/ # GET: query status
│ └── webhooks/antom/ # POST: verify + update
├── lib/
│ ├── antom/ # config, sign, client, types, errors
│ └── orders/ # store interface + memory impl
├── components/ # CheckoutFrame, InlineCheckout, Badge
├── config/ # products, env
└── .env.example
- Private key is server-only (
import 'server-only') - Private key never logged, never in client bundle
- Webhook RSA-verified before processing
- Idempotent webhook handling (by
paymentRequestId) - SDK events used for UI only, never for order fulfillment
- Result page uses server-side
inquiryPaymentfor authority
- Generate separate production RSA key pair
- Upload public key to Antom Dashboard (Production environment)
- Update Vercel env vars (scope: Production only):
ANTOM_CLIENT_ID→ productionANTOM_PRIVATE_KEY→ productionANTOM_PUBLIC_KEY→ production Antom public keyNEXT_PUBLIC_ANTOM_ENV→prod
- Whitelist your custom domain in Antom Dashboard
- Redeploy
The default order store is in-memory (lib/orders/memory.ts). For production:
- Swap with
@vercel/kvfor serverless KV - Or any Postgres / MySQL via your ORM of choice
Replace the export in lib/orders/memory.ts:
export const orderStore: OrderStore = kvOrderStore; // or postgresOrderStore| Symptom | Cause | Fix |
|---|---|---|
SIGN_VERIFY_FAILURE |
Sign string mismatch | Body used for signing must equal body sent |
| Webhook returns 401 | Antom public key wrong | Re-download from Dashboard, single-line base64 |
| CKP shows blank | Session expired (~30 min) | Create a new session |
Missing required env |
Env var not set | Check .env.local or Vercel Settings |
MIT — see LICENSE.
For trademark, AML/CFT/KYC, demonstration-only, and warranty notices, see LEGAL.md.