Skip to main content
Convenience Store (C-Store) payments let customers generate a payment code online and complete their purchase by paying cash or electronically at a participating convenience store chain. This method is widely used in markets such as Indonesia, Japan, and the Philippines, where offline-to-online (O2O) flows are common.

Capabilities & Constraints

  • Flow type: Deferred offline payment (generate code → pay at store → confirm via webhook).
  • Capture model: Direct capture only once customer pays at the store.
  • Customer experience: Customer receives a store code or payment slip → pays at cashier or kiosk → provider posts success.
  • Settlement: According to the local store provider/bank aggregator rules.
  • Refunds/Reversals: Not supported (once customer has paid cash at store, no reversal is possible). Refunds, if needed, must be handled outside Monxa.
  • Expiry: Each store payment code has an expiry time (e.g., 24–48 hours). If not paid, the charge expires automatically.

Supported Channels

ChannelCodeCurrencyRefundSettlementMin AmountMax Amount
Alfamartstore_alfamartIDRN.AT+510,0005,000,000
Indomaretstore_indomaretIDRN.AT+510,0002,500,000

Payment Flow

Status Lifecycle

StatusWhenMerchant Action
pendingCode created; awaiting paymentDisplay code to customer
succeededStore confirmed paymentFulfill order
failedStore rejected / errorOffer retry
expiredNot paid within expiryCreate new charge if needed

Step 1: Create a Charge

Create a charge with a C-Store channel_code. Specify amount, currency, and reference_id. The provider will return store-specific instructions and an expiry.
Endpoint: POST v1/charges
curl https://api.monxa.io/v1/charges \
  -H "Authorization: Bearer sk_test_***" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: chg-cstore-20251009" \
  -d '{
    "amount": 100000,
    "currency": "IDR",
    "reference_id": "INV-2025-1009-001",
    "channel_code": "store_alfamart",
    "channel_properties": {
      "customer_name": "Andi Setiawan"
    },
    "metadata": {
      "note": "Order #991"
    }
  }'
{
	"id": "chg_01JBC9XH2MW01",
	"object": "charge",
	"reference_id": "INV-2025-1009-001",
	"amount": 100000,
	"currency": "IDR",
	"status": "pending",
	"channel_code": "store_alfamart",
	"actions": {
  		"type": "PRESENT_TO_CUSTOMER",
    	"display_code": "123456789012",
    	"instructions": "Present this code at Alfamart cashier before expiry",
    	"expires_at": "2025-10-10T23:59:59Z"
  	},
  	"created_at": "2025-10-09T10:15:00Z"
}

Step 2: Presents Payment Instructions

Show the display_code and store instructions to the customer. Example UX:
  • Online checkout: Display code + barcode/QR for scanning at store.
  • Email/SMS: Send code and expiry details so the customer can pay offline.

Step 3: Customer Pays at Store

Customer visits the selected convenience store, presents the code to cashier or self-service kiosk, and pays the required amount in cash or supported digital methods.

Step 4: Handle Webhooks & Confirm Status

Webhook events:
  • charge.succeeded — Payment confirmed (safe to fulfill).
  • charge.failed — Store rejected or technical error.
  • charge.expired — Customer did not pay before expiry.
{
	"id": "evt_01JBCAXYZ001",
	"type": "charge.succeeded",
	"data": {
		"id": "chg_01JBC9XH2MW01",
		"reference_id": "INV-2025-1009-001",
		"amount": 100000,
		"currency": "IDR",
		"status": "succeeded",
		"channel_code": "store_alfamart",
		"paid_at": "2025-10-09T15:22:33Z"
	},
	"created_at": "2025-10-09T15:22:34Z"
}

Always verify with GET /v1/charges/{id} before updating your order state.

Refunds

❗Not supported.
Once the customer pays cash at a store, funds are final. Any refund must be arranged directly with the customer outside Monxa.

Error Handling

ErrorMeaningHow to Fix
400 unsupported_channelChannel not available in your corridorEnable correct channel
402 amount_out_of_rangeAmount outside allowed limits (e.g., <IDR 10,000)Adjust amount
409 duplicate_referenceSame reference_id already used (if enforced)Use unique ref