{ "info": { "name": "Midtrans Middleware - Payment Link", "description": "Generate & manage shareable Midtrans Snap payment links via the CIFO Midtrans middleware.\n\nFlow: 1) Create Payment Link -> 2) share the returned `data.url` with the customer -> 3) (optional) Resolve Payment Link / Check Status to track it.", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, "variable": [ { "key": "base_url", "value": "http://localhost:8000", "type": "string" }, { "key": "api_key", "value": "dev-key", "type": "string" }, { "key": "order_id", "value": "ERPSKRIP-2608030000000627:TKG-260803000063", "type": "string" }, { "key": "payment_token", "value": "", "type": "string" }, { "key": "midtrans_order_id", "value": "", "type": "string" } ], "item": [ { "name": "Create Payment Link", "request": { "method": "POST", "header": [ { "key": "X-API-KEY", "value": "{{api_key}}" }, { "key": "Content-Type", "value": "application/json" } ], "url": { "raw": "{{base_url}}/api/payment-links", "host": ["{{base_url}}"], "path": ["api", "payment-links"] }, "description": "Creates a signed, shareable Midtrans Snap payment link directly from the given payload.\n\norder_id is used as-is for tracking, and sanitized (':' -> '.') for the value actually sent to Midtrans, since Midtrans order_id only allows alphanumeric and - _ ~ .\n\nexpire_at is honored if it's a future epoch-ms timestamp; otherwise it falls back to PAYMENT_LINK_TTL_MINUTES.\n\nResponse: `{ status, messages, data: { url, order_id, midtrans_order_id, expire_at } }` - `data.url` is the link to share with the customer.", "body": { "mode": "raw", "raw": "{\n \"order_id\": \"ERPSKRIP-2608030000000627:TKG-260803000063\",\n \"nominal\": 179000,\n \"customer\": {\n \"name\": \"Yusnika Nur Faidah\",\n \"phone\": \"0881022144656\",\n \"email\": \"yusnika_nur_faidah@example.com\"\n },\n \"expire_at\": 1785852063058\n}", "options": { "raw": { "language": "json" } } } }, "event": [ { "listen": "test", "script": { "type": "text/javascript", "exec": [ "if (pm.response.code === 200) {", " const data = pm.response.json()?.data || {};", " const token = (data.url || '').split('/').pop();", " if (token) pm.collectionVariables.set('payment_token', token);", " if (data.midtrans_order_id) pm.collectionVariables.set('midtrans_order_id', data.midtrans_order_id);", "}" ] } } ] }, { "name": "Resolve Payment Link", "request": { "method": "GET", "header": [], "url": { "raw": "{{base_url}}/api/payment-links/{{payment_token}}", "host": ["{{base_url}}"], "path": ["api", "payment-links", "{{payment_token}}"] }, "description": "Resolves a payment link token into the underlying order details. Returns `{ order_id, nominal, customer, expire_at, allowed_methods }`. `payment_token` is auto-filled from the \"Create Payment Link\" response." } }, { "name": "Check Payment Status", "request": { "method": "GET", "header": [], "url": { "raw": "{{base_url}}/api/payments/{{midtrans_order_id}}/status", "host": ["{{base_url}}"], "path": ["api", "payments", "{{midtrans_order_id}}", "status"] }, "description": "Checks the current Midtrans transaction status. Uses `midtrans_order_id` (the Midtrans-safe id, ':' replaced with '.'), auto-filled from the \"Create Payment Link\" response." } }, { "name": "Simulate Midtrans Notification (Local)", "request": { "method": "POST", "header": [ { "key": "Content-Type", "value": "application/json" } ], "url": { "raw": "{{base_url}}/api/payments/notification", "host": ["{{base_url}}"], "path": ["api", "payments", "notification"] }, "description": "Replays a REAL webhook payload (copied from Midtrans Dashboard's notification history) straight into the local server, so you can debug the ERP-notify flow without waiting for Midtrans to reach a public URL.\n\nIMPORTANT: `signature_key` in the body must have been generated with the SAME `MIDTRANS_SERVER_KEY` as this local server's `.env` (production key vs sandbox key mismatch = signature invalid). Paste the exact JSON from Dashboard as-is; do not modify order_id/status_code/gross_amount or the signature will no longer match.", "body": { "mode": "raw", "raw": "{\n \"transaction_type\": \"off-us\",\n \"transaction_time\": \"2026-08-03 21:26:58\",\n \"transaction_status\": \"settlement\",\n \"transaction_id\": \"5654e1a9-0d00-4e93-8629-026e6282e4d5\",\n \"status_message\": \"midtrans payment notification\",\n \"status_code\": \"200\",\n \"signature_key\": \"27bad17aac3ca8e2d22096d747d4ea6630237db179df4d3576c93a4300c6bcb72b69c9ca62f90b7af2a005100373b584051406df4f47ec51af4b55bd84de6898\",\n \"settlement_time\": \"2026-08-03 21:31:20\",\n \"pop_id\": \"7c27736b-deb2-483f-a152-2ff50803a3ba\",\n \"payment_type\": \"qris\",\n \"order_id\": \"ERPSKRIP-2608030000000637.TKG-260801001361\",\n \"merchant_id\": \"G277033254\",\n \"merchant_cross_reference_id\": \"d65f691f-4ba1-4dc6-a6eb-bd3f3303416a\",\n \"issuer\": \"BJB\",\n \"gross_amount\": \"159000.00\",\n \"fraud_status\": \"accept\",\n \"expiry_time\": \"2026-08-04 21:26:58\",\n \"customer_details\": {\n \"phone\": \"+6281952988381\",\n \"full_name\": \"Saepudin \",\n \"email\": \"saepudin@example.com\"\n },\n \"currency\": \"IDR\",\n \"acquirer\": \"gopay\"\n}", "options": { "raw": { "language": "json" } } } } }, { "name": "Health Check", "request": { "method": "GET", "header": [], "url": { "raw": "{{base_url}}/api/health", "host": ["{{base_url}}"], "path": ["api", "health"] }, "description": "Server + Midtrans key configuration health check." } } ] }