{
  "item": [
    {
      "id": "778e3976-e57e-4f58-82e7-b13760f17d5d",
      "name": "Authentication",
      "description": "BSync Public API authentication uses a static Bearer API key — there is no token exchange endpoint.\n\nSet `apiKey` in your active environment:\n- Test: `bsync_test_...`\n- Live: `bsync_live_...`\n\nCreate keys in the BSync Dashboard under API Keys.",
      "item": [
        {
          "id": "3ffe496f-2a36-4e5a-a749-6f51dbbe8aee",
          "name": "Missing API Key (401)",
          "request": {
            "name": "Create a payment intent",
            "description": {
              "content": "Creates a new payment intent and returns a Hosted Checkout URL.\nOptionally send `Idempotency-Key` to safely retry without duplicate payments.\n",
              "type": "text/plain"
            },
            "url": {
              "path": [
                "v1",
                "payment-intents"
              ],
              "host": [
                "{{baseUrl}}"
              ],
              "query": [],
              "variable": [],
              "raw": "{{baseUrl}}/v1/payment-intents"
            },
            "header": [
              {
                "disabled": true,
                "description": "Optional idempotency key. Same key + same body replays the stored response.",
                "key": "Idempotency-Key",
                "value": "{{idempotencyKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"amount\": 150,\n  \"customerPhone\": \"+201012345678\",\n  \"externalOrderId\": \"ORD-123\",\n  \"currency\": \"EGP\",\n  \"successUrl\": \"https://merchant.com/checkout/success\",\n  \"cancelUrl\": \"https://merchant.com/checkout/cancel\",\n  \"redirectDelay\": 5,\n  \"metadata\": {\n    \"description\": \"Order 123\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "auth": {
              "type": "noauth"
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('Status code is 201', function () { pm.response.to.have.status(201); });",
                  "const json = pm.response.json();",
                  "pm.test('Success envelope with paymentId', function () {",
                  "  pm.expect(json.success).to.eql(true);",
                  "  pm.expect(json.data).to.have.property('paymentId');",
                  "  pm.expect(json.data).to.have.property('checkoutUrl');",
                  "});",
                  "const jsonCreate = pm.response.json();",
                  "if (jsonCreate.data) {",
                  "  pm.environment.set('paymentId', jsonCreate.data.paymentId);",
                  "  pm.environment.set('checkoutUrl', jsonCreate.data.checkoutUrl);",
                  "  if (jsonCreate.data.expiresAt) pm.environment.set('expiresAt', jsonCreate.data.expiresAt);",
                  "  const parts = String(jsonCreate.data.checkoutUrl || '').split('/');",
                  "  pm.environment.set('checkoutToken', parts[parts.length - 1] || '');",
                  "}",
                  "pm.test('Response time under 5000ms', function () {",
                  "  pm.expect(pm.response.responseTime).to.be.below(5000);",
                  "});",
                  "const requestId = pm.response.headers.get('X-Request-ID');",
                  "if (requestId) { pm.environment.set('requestId', requestId); }",
                  "pm.test('Status code is 401', function () { pm.response.to.have.status(401); });",
                  "const json = pm.response.json();",
                  "pm.test('Authentication error envelope', function () {",
                  "  pm.expect(json.success).to.eql(false);",
                  "  pm.expect(json.error.type).to.eql('authentication_error');",
                  "});"
                ]
              }
            }
          ],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        }
      ],
      "event": []
    },
    {
      "id": "69efb8c7-62f6-4312-b4c9-2eab984739e0",
      "name": "Payment Intents",
      "description": {
        "content": "Create, read, poll status, and cancel payment intents.",
        "type": "text/plain"
      },
      "item": [
        {
          "id": "3ffe496f-2a36-4e5a-a749-6f51dbbe8aee",
          "name": "Create a payment intent",
          "request": {
            "name": "Create a payment intent",
            "description": {
              "content": "Creates a new payment intent and returns a Hosted Checkout URL.\nOptionally send `Idempotency-Key` to safely retry without duplicate payments.\n",
              "type": "text/plain"
            },
            "url": {
              "path": [
                "v1",
                "payment-intents"
              ],
              "host": [
                "{{baseUrl}}"
              ],
              "query": [],
              "variable": [],
              "raw": "{{baseUrl}}/v1/payment-intents"
            },
            "header": [
              {
                "disabled": true,
                "description": "Optional idempotency key. Same key + same body replays the stored response.",
                "key": "Idempotency-Key",
                "value": "{{idempotencyKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"amount\": 150,\n  \"customerPhone\": \"+201012345678\",\n  \"externalOrderId\": \"ORD-123\",\n  \"currency\": \"EGP\",\n  \"successUrl\": \"https://merchant.com/checkout/success\",\n  \"cancelUrl\": \"https://merchant.com/checkout/cancel\",\n  \"redirectDelay\": 5,\n  \"metadata\": {\n    \"description\": \"Order 123\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('Status code is 201', function () { pm.response.to.have.status(201); });",
                  "const json = pm.response.json();",
                  "pm.test('Success envelope with paymentId', function () {",
                  "  pm.expect(json.success).to.eql(true);",
                  "  pm.expect(json.data).to.have.property('paymentId');",
                  "  pm.expect(json.data).to.have.property('checkoutUrl');",
                  "});",
                  "const jsonCreate = pm.response.json();",
                  "if (jsonCreate.data) {",
                  "  pm.environment.set('paymentId', jsonCreate.data.paymentId);",
                  "  pm.environment.set('checkoutUrl', jsonCreate.data.checkoutUrl);",
                  "  if (jsonCreate.data.expiresAt) pm.environment.set('expiresAt', jsonCreate.data.expiresAt);",
                  "  const parts = String(jsonCreate.data.checkoutUrl || '').split('/');",
                  "  pm.environment.set('checkoutToken', parts[parts.length - 1] || '');",
                  "}",
                  "pm.test('Response time under 5000ms', function () {",
                  "  pm.expect(pm.response.responseTime).to.be.below(5000);",
                  "});",
                  "const requestId = pm.response.headers.get('X-Request-ID');",
                  "if (requestId) { pm.environment.set('requestId', requestId); }"
                ]
              }
            }
          ],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        },
        {
          "id": "a84c87c5-abac-4e85-8147-eb4419a57c22",
          "name": "Get payment intent",
          "request": {
            "name": "Get payment intent",
            "description": {
              "content": "Returns the payment intent when it exists in the same environment as the API key.\nCross-environment access (test key on a live payment, or vice versa) returns **404**\nwith `RESOURCE_NOT_FOUND` to avoid resource enumeration (DISC-008).\n",
              "type": "text/plain"
            },
            "url": {
              "path": [
                "v1",
                "payment-intents",
                "{{paymentId}}"
              ],
              "host": [
                "{{baseUrl}}"
              ],
              "query": [],
              "variable": [
                {
                  "disabled": false,
                  "type": "any",
                  "value": "{{paymentId}}",
                  "key": "paymentId",
                  "description": "(Required) "
                }
              ],
              "raw": "{{baseUrl}}/v1/payment-intents/{{paymentId}}"
            },
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('Status code is 200', function () { pm.response.to.have.status(200); });",
                  "const json = pm.response.json();",
                  "pm.test('Payment intent returned', function () {",
                  "  pm.expect(json.success).to.eql(true);",
                  "  pm.expect(json.data.paymentId).to.eql(pm.environment.get('paymentId'));",
                  "});",
                  "pm.test('Response time under 5000ms', function () {",
                  "  pm.expect(pm.response.responseTime).to.be.below(5000);",
                  "});",
                  "const requestId = pm.response.headers.get('X-Request-ID');",
                  "if (requestId) { pm.environment.set('requestId', requestId); }"
                ]
              }
            }
          ],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        },
        {
          "id": "61bec12d-4556-4a14-bd74-d42b58ec3836",
          "name": "Get lightweight payment status",
          "request": {
            "name": "Get lightweight payment status",
            "description": {
              "content": "Polling-friendly status DTO with six fields only.\nCross-environment access returns **404** with `RESOURCE_NOT_FOUND` (DISC-008).\n",
              "type": "text/plain"
            },
            "url": {
              "path": [
                "v1",
                "payment-intents",
                "{{paymentId}}",
                "status"
              ],
              "host": [
                "{{baseUrl}}"
              ],
              "query": [],
              "variable": [
                {
                  "disabled": false,
                  "type": "any",
                  "value": "{{paymentId}}",
                  "key": "paymentId",
                  "description": "(Required) "
                }
              ],
              "raw": "{{baseUrl}}/v1/payment-intents/{{paymentId}}/status"
            },
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('Status code is 200', function () { pm.response.to.have.status(200); });",
                  "const json = pm.response.json();",
                  "pm.test('Status DTO shape', function () {",
                  "  pm.expect(json.success).to.eql(true);",
                  "  pm.expect(json.data).to.have.keys('paymentId', 'status', 'matchStatus', 'verificationStatus', 'paidAt', 'updatedAt');",
                  "});",
                  "pm.test('API-Version header is v1', function () {",
                  "  pm.expect(pm.response.headers.get('API-Version')).to.eql('v1');",
                  "});",
                  "pm.test('Deprecation header is false', function () {",
                  "  pm.expect(pm.response.headers.get('Deprecation')).to.eql('false');",
                  "});",
                  "pm.test('Response time under 5000ms', function () {",
                  "  pm.expect(pm.response.responseTime).to.be.below(5000);",
                  "});",
                  "const requestId = pm.response.headers.get('X-Request-ID');",
                  "if (requestId) { pm.environment.set('requestId', requestId); }"
                ]
              }
            }
          ],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        },
        {
          "id": "234db5d3-8247-47aa-a1b2-7a7673125cf8",
          "name": "Cancel a pending payment intent",
          "request": {
            "name": "Cancel a pending payment intent",
            "description": {
              "content": "Cancels a pending payment intent in the same environment as the API key.\nCross-environment access returns **404** with `RESOURCE_NOT_FOUND` (DISC-008).\n",
              "type": "text/plain"
            },
            "url": {
              "path": [
                "v1",
                "payment-intents",
                "{{paymentId}}",
                "cancel"
              ],
              "host": [
                "{{baseUrl}}"
              ],
              "query": [],
              "variable": [
                {
                  "disabled": false,
                  "type": "any",
                  "value": "{{paymentId}}",
                  "key": "paymentId",
                  "description": "(Required) "
                }
              ],
              "raw": "{{baseUrl}}/v1/payment-intents/{{paymentId}}/cancel"
            },
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "POST"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('Status code is 200', function () { pm.response.to.have.status(200); });",
                  "const json = pm.response.json();",
                  "pm.test('Cancelled payment intent', function () {",
                  "  pm.expect(json.success).to.eql(true);",
                  "  pm.expect(json.data.status).to.eql('cancelled');",
                  "});",
                  "pm.test('Response time under 5000ms', function () {",
                  "  pm.expect(pm.response.responseTime).to.be.below(5000);",
                  "});",
                  "const requestId = pm.response.headers.get('X-Request-ID');",
                  "if (requestId) { pm.environment.set('requestId', requestId); }"
                ]
              }
            }
          ],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        }
      ],
      "event": []
    },
    {
      "id": "3f9c100d-b908-4c75-b2d9-abd7d7e34ea3",
      "name": "Hosted Checkout",
      "description": {
        "content": "Customer-facing checkout session (token auth in path, not API key).",
        "type": "text/plain"
      },
      "item": [
        {
          "id": "a71138b3-2b4a-4fb5-978d-d797dcaf38a4",
          "name": "Load checkout session",
          "request": {
            "name": "Load checkout session",
            "description": {
              "content": "Customer-facing checkout page bootstrap. Authenticated by checkout token in path.",
              "type": "text/plain"
            },
            "url": {
              "path": [
                "checkout",
                "{{checkoutToken}}"
              ],
              "host": [
                "{{baseUrl}}"
              ],
              "query": [],
              "variable": [
                {
                  "disabled": false,
                  "type": "any",
                  "value": "{{checkoutToken}}",
                  "key": "token",
                  "description": "(Required) "
                }
              ],
              "raw": "{{baseUrl}}/checkout/{{checkoutToken}}"
            },
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('Status code is 200', function () { pm.response.to.have.status(200); });",
                  "pm.test('Response time under 5000ms', function () {",
                  "  pm.expect(pm.response.responseTime).to.be.below(5000);",
                  "});",
                  "const requestId = pm.response.headers.get('X-Request-ID');",
                  "if (requestId) { pm.environment.set('requestId', requestId); }"
                ]
              }
            }
          ],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        },
        {
          "id": "e7b1b98b-93b6-41fb-a3ee-0bab0db7ee70",
          "name": "Get checkout session status",
          "request": {
            "name": "Get checkout session status",
            "description": {},
            "url": {
              "path": [
                "checkout",
                "{{checkoutToken}}",
                "status"
              ],
              "host": [
                "{{baseUrl}}"
              ],
              "query": [],
              "variable": [
                {
                  "disabled": false,
                  "type": "any",
                  "value": "{{checkoutToken}}",
                  "key": "token",
                  "description": "(Required) "
                }
              ],
              "raw": "{{baseUrl}}/checkout/{{checkoutToken}}/status"
            },
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('Status code is 200', function () { pm.response.to.have.status(200); });",
                  "pm.test('Response time under 5000ms', function () {",
                  "  pm.expect(pm.response.responseTime).to.be.below(5000);",
                  "});",
                  "const requestId = pm.response.headers.get('X-Request-ID');",
                  "if (requestId) { pm.environment.set('requestId', requestId); }"
                ]
              }
            }
          ],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        },
        {
          "id": "ab665e5a-49fd-4c16-8a48-fd3cb01daf4f",
          "name": "Get payment instructions",
          "request": {
            "name": "Get payment instructions",
            "description": {
              "content": "Requires provider and sender phone to be set first.",
              "type": "text/plain"
            },
            "url": {
              "path": [
                "checkout",
                "{{checkoutToken}}",
                "instructions"
              ],
              "host": [
                "{{baseUrl}}"
              ],
              "query": [],
              "variable": [
                {
                  "disabled": false,
                  "type": "any",
                  "value": "{{checkoutToken}}",
                  "key": "token",
                  "description": "(Required) "
                }
              ],
              "raw": "{{baseUrl}}/checkout/{{checkoutToken}}/instructions"
            },
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET"
          },
          "event": [],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        },
        {
          "id": "c8038608-3cd3-4d66-a057-977a9b729551",
          "name": "Select payment provider",
          "request": {
            "name": "Select payment provider",
            "description": {},
            "url": {
              "path": [
                "checkout",
                "{{checkoutToken}}",
                "provider"
              ],
              "host": [
                "{{baseUrl}}"
              ],
              "query": [],
              "variable": [
                {
                  "disabled": false,
                  "type": "any",
                  "value": "{{checkoutToken}}",
                  "key": "token",
                  "description": "(Required) "
                }
              ],
              "raw": "{{baseUrl}}/checkout/{{checkoutToken}}/provider"
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"provider\": \"vodafone-cash\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        },
        {
          "id": "9a178221-5716-49df-a6f6-4949bd634e2b",
          "name": "Submit sender phone number",
          "request": {
            "name": "Submit sender phone number",
            "description": {},
            "url": {
              "path": [
                "checkout",
                "{{checkoutToken}}",
                "sender"
              ],
              "host": [
                "{{baseUrl}}"
              ],
              "query": [],
              "variable": [
                {
                  "disabled": false,
                  "type": "any",
                  "value": "{{checkoutToken}}",
                  "key": "token",
                  "description": "(Required) "
                }
              ],
              "raw": "{{baseUrl}}/checkout/{{checkoutToken}}/sender"
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"senderPhone\": \"+201012345678\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        },
        {
          "id": "05b8b4d0-1eaa-4a32-aaa4-0188c8df29cf",
          "name": "Subscribe to checkout Server-Sent Events",
          "request": {
            "name": "Subscribe to checkout Server-Sent Events",
            "description": {
              "content": "Real-time checkout updates over SSE (`text/event-stream`).\n\n**Connection:** Initial line `retry: 3000` (reconnect hint in milliseconds).\n\n**Heartbeat:** Every 30 seconds — comment `: ping {timestamp}` and event `heartbeat` with `{ \"timestamp\": \"<ISO8601>\" }`.\n\n**Terminal events** (stream closes after emit): `payment_confirmed`, `payment_expired`, `payment_cancelled`, `payment_failed`.\n\n**Wire format:**\n```\nevent: payment_confirmed\ndata: {\"paymentId\":\"PAY_ABC123\",\"checkoutStatus\":\"paid\",...}\n\n```\n\n**Event catalog:**\n\n| SSE event | Trigger |\n|-----------|---------|\n| `checkout_connected` | Initial connection |\n| `payment_waiting` | Payment created |\n| `payment_detected` | SMS matched |\n| `payment_confirmed` | Payment paid (terminal) |\n| `payment_review_required` | Manual review needed |\n| `payment_failed` | Review rejected (terminal) |\n| `payment_expired` | Session expired (terminal) |\n| `payment_cancelled` | Cancelled (terminal) |\n| `heartbeat` | Keep-alive |\n| `server_shutdown` | Server restart `{ \"retryAfter\": 5 }` |\n",
              "type": "text/plain"
            },
            "url": {
              "path": [
                "checkout",
                "{{checkoutToken}}",
                "events"
              ],
              "host": [
                "{{baseUrl}}"
              ],
              "query": [],
              "variable": [
                {
                  "disabled": false,
                  "type": "any",
                  "value": "{{checkoutToken}}",
                  "key": "token",
                  "description": "(Required) "
                }
              ],
              "raw": "{{baseUrl}}/checkout/{{checkoutToken}}/events"
            },
            "header": [
              {
                "key": "Accept",
                "value": "text/event-stream"
              }
            ],
            "method": "GET"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('Status code is 200', function () { pm.response.to.have.status(200); });",
                  "pm.test('Content-Type is event-stream', function () {",
                  "  pm.expect(pm.response.headers.get('Content-Type')).to.include('text/event-stream');",
                  "});",
                  "pm.test('Response time under 5000ms', function () {",
                  "  pm.expect(pm.response.responseTime).to.be.below(5000);",
                  "});",
                  "const requestId = pm.response.headers.get('X-Request-ID');",
                  "if (requestId) { pm.environment.set('requestId', requestId); }"
                ]
              }
            }
          ],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        }
      ],
      "event": []
    },
    {
      "name": "Webhooks",
      "description": "Outbound webhook events delivered by BSync to your server endpoint.\n\n**Headers:** `X-BSYNC-EVENT`, `X-BSYNC-SIGNATURE` (HMAC-SHA256 hex of raw JSON body), `Content-Type: application/json`\n\n**Retry policy:** 5 attempts with backoff 1m / 5m / 15m / 1h. Statuses: pending, success, failed, retrying, dead_letter.\n\n**Signature verification (Node.js):**\n```javascript\nconst crypto = require('crypto');\nconst secret = process.env.BSYNC_WEBHOOK_SECRET;\nconst rawBody = JSON.stringify(req.body);\nconst expected = crypto.createHmac('sha256', secret).update(rawBody).digest('hex');\nconst signature = req.headers['x-bsync-signature'];\ncrypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));\n```\n\nSet `webhookUrl` in your environment to your local webhook receiver URL before sending sample payloads.\n\n[object Object]",
      "item": [
        {
          "id": "567f436e-be10-46d7-9da5-2c8880e85bae",
          "name": "PAYMENT_CREATED",
          "request": {
            "name": "PAYMENT_CREATED",
            "description": {
              "content": "Fired when a payment intent is created via the API.",
              "type": "text/plain"
            },
            "url": {
              "host": [
                "{{webhookUrl}}"
              ],
              "query": [],
              "variable": [],
              "raw": "{{webhookUrl}}",
              "path": []
            },
            "header": [
              {
                "disabled": false,
                "description": "(Required) Event type matching `eventType` in the body.",
                "key": "X-BSYNC-EVENT",
                "value": "PAYMENT_CREATED"
              },
              {
                "disabled": false,
                "description": "(Required) HMAC-SHA256 hex digest of the raw JSON request body, keyed with your webhook secret.",
                "key": "X-BSYNC-SIGNATURE",
                "value": "string"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"value\": \"<Error: Could not resolve allOf schema\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        },
        {
          "id": "73a9021c-1913-421d-8f8b-82babcf1cd5a",
          "name": "PAYMENT_MATCHED",
          "request": {
            "name": "PAYMENT_MATCHED",
            "description": {},
            "url": {
              "host": [
                "{{webhookUrl}}"
              ],
              "query": [],
              "variable": [],
              "raw": "{{webhookUrl}}",
              "path": []
            },
            "header": [
              {
                "disabled": false,
                "description": "(Required) Event type matching `eventType` in the body.",
                "key": "X-BSYNC-EVENT",
                "value": "PAYMENT_MATCHED"
              },
              {
                "disabled": false,
                "description": "(Required) HMAC-SHA256 hex digest of the raw JSON request body, keyed with your webhook secret.",
                "key": "X-BSYNC-SIGNATURE",
                "value": "string"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"value\": \"<Error: Could not resolve allOf schema\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        },
        {
          "id": "bb4b1f2c-6791-430e-add1-650762007fbf",
          "name": "PAYMENT_PAID",
          "request": {
            "name": "PAYMENT_PAID",
            "description": {
              "content": "Primary success event for merchant order fulfillment.",
              "type": "text/plain"
            },
            "url": {
              "host": [
                "{{webhookUrl}}"
              ],
              "query": [],
              "variable": [],
              "raw": "{{webhookUrl}}",
              "path": []
            },
            "header": [
              {
                "disabled": false,
                "description": "(Required) Event type matching `eventType` in the body.",
                "key": "X-BSYNC-EVENT",
                "value": "PAYMENT_PAID"
              },
              {
                "disabled": false,
                "description": "(Required) HMAC-SHA256 hex digest of the raw JSON request body, keyed with your webhook secret.",
                "key": "X-BSYNC-SIGNATURE",
                "value": "string"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"value\": \"<Error: Could not resolve allOf schema\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        },
        {
          "id": "ca259588-3998-454e-a96a-80f4bbfbd269",
          "name": "PAYMENT_CANCELLED",
          "request": {
            "name": "PAYMENT_CANCELLED",
            "description": {},
            "url": {
              "host": [
                "{{webhookUrl}}"
              ],
              "query": [],
              "variable": [],
              "raw": "{{webhookUrl}}",
              "path": []
            },
            "header": [
              {
                "disabled": false,
                "description": "(Required) Event type matching `eventType` in the body.",
                "key": "X-BSYNC-EVENT",
                "value": "PAYMENT_CANCELLED"
              },
              {
                "disabled": false,
                "description": "(Required) HMAC-SHA256 hex digest of the raw JSON request body, keyed with your webhook secret.",
                "key": "X-BSYNC-SIGNATURE",
                "value": "string"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"value\": \"<Error: Could not resolve allOf schema\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        },
        {
          "id": "f7f5186d-ab9a-443d-b276-54d5d968463f",
          "name": "PAYMENT_EXPIRED",
          "request": {
            "name": "PAYMENT_EXPIRED",
            "description": {},
            "url": {
              "host": [
                "{{webhookUrl}}"
              ],
              "query": [],
              "variable": [],
              "raw": "{{webhookUrl}}",
              "path": []
            },
            "header": [
              {
                "disabled": false,
                "description": "(Required) Event type matching `eventType` in the body.",
                "key": "X-BSYNC-EVENT",
                "value": "PAYMENT_EXPIRED"
              },
              {
                "disabled": false,
                "description": "(Required) HMAC-SHA256 hex digest of the raw JSON request body, keyed with your webhook secret.",
                "key": "X-BSYNC-SIGNATURE",
                "value": "string"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"value\": \"<Error: Could not resolve allOf schema\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        },
        {
          "id": "6a966486-55f1-4a8c-b340-4638e18ced12",
          "name": "PAYMENT_REVIEW_REQUIRED",
          "request": {
            "name": "PAYMENT_REVIEW_REQUIRED",
            "description": {},
            "url": {
              "host": [
                "{{webhookUrl}}"
              ],
              "query": [],
              "variable": [],
              "raw": "{{webhookUrl}}",
              "path": []
            },
            "header": [
              {
                "disabled": false,
                "description": "(Required) Event type matching `eventType` in the body.",
                "key": "X-BSYNC-EVENT",
                "value": "PAYMENT_REVIEW_REQUIRED"
              },
              {
                "disabled": false,
                "description": "(Required) HMAC-SHA256 hex digest of the raw JSON request body, keyed with your webhook secret.",
                "key": "X-BSYNC-SIGNATURE",
                "value": "string"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"value\": \"<Error: Could not resolve allOf schema\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        },
        {
          "id": "834f1259-5dbe-4fe1-9657-7afb88d70f10",
          "name": "PAYMENT_REVIEW_APPROVED",
          "request": {
            "name": "PAYMENT_REVIEW_APPROVED",
            "description": {},
            "url": {
              "host": [
                "{{webhookUrl}}"
              ],
              "query": [],
              "variable": [],
              "raw": "{{webhookUrl}}",
              "path": []
            },
            "header": [
              {
                "disabled": false,
                "description": "(Required) Event type matching `eventType` in the body.",
                "key": "X-BSYNC-EVENT",
                "value": "PAYMENT_REVIEW_APPROVED"
              },
              {
                "disabled": false,
                "description": "(Required) HMAC-SHA256 hex digest of the raw JSON request body, keyed with your webhook secret.",
                "key": "X-BSYNC-SIGNATURE",
                "value": "string"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"value\": \"<Error: Could not resolve allOf schema\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        },
        {
          "id": "54cf0514-4e75-4323-a287-8f906ab1600c",
          "name": "PAYMENT_REVIEW_REJECTED",
          "request": {
            "name": "PAYMENT_REVIEW_REJECTED",
            "description": {},
            "url": {
              "host": [
                "{{webhookUrl}}"
              ],
              "query": [],
              "variable": [],
              "raw": "{{webhookUrl}}",
              "path": []
            },
            "header": [
              {
                "disabled": false,
                "description": "(Required) Event type matching `eventType` in the body.",
                "key": "X-BSYNC-EVENT",
                "value": "PAYMENT_REVIEW_REJECTED"
              },
              {
                "disabled": false,
                "description": "(Required) HMAC-SHA256 hex digest of the raw JSON request body, keyed with your webhook secret.",
                "key": "X-BSYNC-SIGNATURE",
                "value": "string"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"value\": \"<Error: Could not resolve allOf schema\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        }
      ]
    },
    {
      "id": "66c23970-c02b-4563-9678-7e017cae6e84",
      "name": "System",
      "description": "Platform metadata and version headers returned on every /v1 response.",
      "item": [
        {
          "id": "61bec12d-4556-4a14-bd74-d42b58ec3836",
          "name": "Verify API Version Headers",
          "request": {
            "name": "Get lightweight payment status",
            "description": {
              "content": "Polling-friendly status DTO with six fields only.\nCross-environment access returns **404** with `RESOURCE_NOT_FOUND` (DISC-008).\n",
              "type": "text/plain"
            },
            "url": {
              "path": [
                "v1",
                "payment-intents",
                "{{paymentId}}",
                "status"
              ],
              "host": [
                "{{baseUrl}}"
              ],
              "query": [],
              "variable": [
                {
                  "disabled": false,
                  "type": "any",
                  "value": "{{paymentId}}",
                  "key": "paymentId",
                  "description": "(Required) "
                }
              ],
              "raw": "{{baseUrl}}/v1/payment-intents/{{paymentId}}/status"
            },
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('Status code is 200', function () { pm.response.to.have.status(200); });",
                  "const json = pm.response.json();",
                  "pm.test('Status DTO shape', function () {",
                  "  pm.expect(json.success).to.eql(true);",
                  "  pm.expect(json.data).to.have.keys('paymentId', 'status', 'matchStatus', 'verificationStatus', 'paidAt', 'updatedAt');",
                  "});",
                  "pm.test('API-Version header is v1', function () {",
                  "  pm.expect(pm.response.headers.get('API-Version')).to.eql('v1');",
                  "});",
                  "pm.test('Deprecation header is false', function () {",
                  "  pm.expect(pm.response.headers.get('Deprecation')).to.eql('false');",
                  "});",
                  "pm.test('Response time under 5000ms', function () {",
                  "  pm.expect(pm.response.responseTime).to.be.below(5000);",
                  "});",
                  "const requestId = pm.response.headers.get('X-Request-ID');",
                  "if (requestId) { pm.environment.set('requestId', requestId); }",
                  "pm.test('Status code is 200', function () { pm.response.to.have.status(200); });",
                  "pm.test('API-Version header is v1', function () {",
                  "  pm.expect(pm.response.headers.get('API-Version')).to.eql('v1');",
                  "});",
                  "pm.test('Deprecation header is false', function () {",
                  "  pm.expect(pm.response.headers.get('Deprecation')).to.eql('false');",
                  "});",
                  "pm.test('X-BSync-Version header is v1', function () {",
                  "  pm.expect(pm.response.headers.get('X-BSync-Version')).to.eql('v1');",
                  "});"
                ]
              }
            }
          ],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        }
      ],
      "event": []
    },
    {
      "name": "Errors",
      "item": [
        {
          "id": "3ffe496f-2a36-4e5a-a749-6f51dbbe8aee",
          "name": "Validation Error (400)",
          "request": {
            "name": "Create a payment intent",
            "description": {
              "content": "Creates a new payment intent and returns a Hosted Checkout URL.\nOptionally send `Idempotency-Key` to safely retry without duplicate payments.\n",
              "type": "text/plain"
            },
            "url": {
              "path": [
                "v1",
                "payment-intents"
              ],
              "host": [
                "{{baseUrl}}"
              ],
              "query": [],
              "variable": [],
              "raw": "{{baseUrl}}/v1/payment-intents"
            },
            "header": [
              {
                "disabled": true,
                "description": "Optional idempotency key. Same key + same body replays the stored response.",
                "key": "Idempotency-Key",
                "value": "{{idempotencyKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"amount\": -1,\n  \"currency\": \"EGP\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('Status code is 201', function () { pm.response.to.have.status(201); });",
                  "const json = pm.response.json();",
                  "pm.test('Success envelope with paymentId', function () {",
                  "  pm.expect(json.success).to.eql(true);",
                  "  pm.expect(json.data).to.have.property('paymentId');",
                  "  pm.expect(json.data).to.have.property('checkoutUrl');",
                  "});",
                  "const jsonCreate = pm.response.json();",
                  "if (jsonCreate.data) {",
                  "  pm.environment.set('paymentId', jsonCreate.data.paymentId);",
                  "  pm.environment.set('checkoutUrl', jsonCreate.data.checkoutUrl);",
                  "  if (jsonCreate.data.expiresAt) pm.environment.set('expiresAt', jsonCreate.data.expiresAt);",
                  "  const parts = String(jsonCreate.data.checkoutUrl || '').split('/');",
                  "  pm.environment.set('checkoutToken', parts[parts.length - 1] || '');",
                  "}",
                  "pm.test('Response time under 5000ms', function () {",
                  "  pm.expect(pm.response.responseTime).to.be.below(5000);",
                  "});",
                  "const requestId = pm.response.headers.get('X-Request-ID');",
                  "if (requestId) { pm.environment.set('requestId', requestId); }",
                  "pm.test('Status code is 400', function () { pm.response.to.have.status(400); });",
                  "const json = pm.response.json();",
                  "pm.test('Validation error envelope', function () {",
                  "  pm.expect(json.success).to.eql(false);",
                  "  pm.expect(json.error.type).to.eql('validation_error');",
                  "});"
                ]
              }
            }
          ],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        },
        {
          "id": "3ffe496f-2a36-4e5a-a749-6f51dbbe8aee",
          "name": "Authentication Failure (401)",
          "request": {
            "name": "Create a payment intent",
            "description": {
              "content": "Creates a new payment intent and returns a Hosted Checkout URL.\nOptionally send `Idempotency-Key` to safely retry without duplicate payments.\n",
              "type": "text/plain"
            },
            "url": {
              "path": [
                "v1",
                "payment-intents"
              ],
              "host": [
                "{{baseUrl}}"
              ],
              "query": [],
              "variable": [],
              "raw": "{{baseUrl}}/v1/payment-intents"
            },
            "header": [
              {
                "disabled": true,
                "description": "Optional idempotency key. Same key + same body replays the stored response.",
                "key": "Idempotency-Key",
                "value": "{{idempotencyKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"amount\": 150,\n  \"customerPhone\": \"+201012345678\",\n  \"externalOrderId\": \"ORD-123\",\n  \"currency\": \"EGP\",\n  \"successUrl\": \"https://merchant.com/checkout/success\",\n  \"cancelUrl\": \"https://merchant.com/checkout/cancel\",\n  \"redirectDelay\": 5,\n  \"metadata\": {\n    \"description\": \"Order 123\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "auth": {
              "type": "bearer",
              "bearer": [
                {
                  "key": "token",
                  "value": "bsync_test_invalid_key",
                  "type": "string"
                }
              ]
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('Status code is 201', function () { pm.response.to.have.status(201); });",
                  "const json = pm.response.json();",
                  "pm.test('Success envelope with paymentId', function () {",
                  "  pm.expect(json.success).to.eql(true);",
                  "  pm.expect(json.data).to.have.property('paymentId');",
                  "  pm.expect(json.data).to.have.property('checkoutUrl');",
                  "});",
                  "const jsonCreate = pm.response.json();",
                  "if (jsonCreate.data) {",
                  "  pm.environment.set('paymentId', jsonCreate.data.paymentId);",
                  "  pm.environment.set('checkoutUrl', jsonCreate.data.checkoutUrl);",
                  "  if (jsonCreate.data.expiresAt) pm.environment.set('expiresAt', jsonCreate.data.expiresAt);",
                  "  const parts = String(jsonCreate.data.checkoutUrl || '').split('/');",
                  "  pm.environment.set('checkoutToken', parts[parts.length - 1] || '');",
                  "}",
                  "pm.test('Response time under 5000ms', function () {",
                  "  pm.expect(pm.response.responseTime).to.be.below(5000);",
                  "});",
                  "const requestId = pm.response.headers.get('X-Request-ID');",
                  "if (requestId) { pm.environment.set('requestId', requestId); }",
                  "pm.test('Status code is 401', function () { pm.response.to.have.status(401); });",
                  "const json = pm.response.json();",
                  "pm.test('Authentication error envelope', function () {",
                  "  pm.expect(json.success).to.eql(false);",
                  "  pm.expect(json.error.type).to.eql('authentication_error');",
                  "});"
                ]
              }
            }
          ],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        },
        {
          "id": "3ffe496f-2a36-4e5a-a749-6f51dbbe8aee",
          "name": "Idempotency Conflict — Step 1 (create)",
          "request": {
            "name": "Create a payment intent",
            "description": {
              "content": "Creates a new payment intent and returns a Hosted Checkout URL.\nOptionally send `Idempotency-Key` to safely retry without duplicate payments.\n",
              "type": "text/plain"
            },
            "url": {
              "path": [
                "v1",
                "payment-intents"
              ],
              "host": [
                "{{baseUrl}}"
              ],
              "query": [],
              "variable": [],
              "raw": "{{baseUrl}}/v1/payment-intents"
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "postman-conflict-demo-key",
                "type": "text"
              }
            ],
            "method": "POST",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"amount\": 150,\n  \"customerPhone\": \"+201012345678\",\n  \"externalOrderId\": \"ORD-123\",\n  \"currency\": \"EGP\",\n  \"successUrl\": \"https://merchant.com/checkout/success\",\n  \"cancelUrl\": \"https://merchant.com/checkout/cancel\",\n  \"redirectDelay\": 5,\n  \"metadata\": {\n    \"description\": \"Order 123\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('Status code is 201', function () { pm.response.to.have.status(201); });",
                  "const json = pm.response.json();",
                  "pm.test('Success envelope with paymentId', function () {",
                  "  pm.expect(json.success).to.eql(true);",
                  "  pm.expect(json.data).to.have.property('paymentId');",
                  "  pm.expect(json.data).to.have.property('checkoutUrl');",
                  "});",
                  "const jsonCreate = pm.response.json();",
                  "if (jsonCreate.data) {",
                  "  pm.environment.set('paymentId', jsonCreate.data.paymentId);",
                  "  pm.environment.set('checkoutUrl', jsonCreate.data.checkoutUrl);",
                  "  if (jsonCreate.data.expiresAt) pm.environment.set('expiresAt', jsonCreate.data.expiresAt);",
                  "  const parts = String(jsonCreate.data.checkoutUrl || '').split('/');",
                  "  pm.environment.set('checkoutToken', parts[parts.length - 1] || '');",
                  "}",
                  "pm.test('Response time under 5000ms', function () {",
                  "  pm.expect(pm.response.responseTime).to.be.below(5000);",
                  "});",
                  "const requestId = pm.response.headers.get('X-Request-ID');",
                  "if (requestId) { pm.environment.set('requestId', requestId); }",
                  "pm.test('Status code is 201', function () { pm.response.to.have.status(201); });"
                ]
              }
            }
          ],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        },
        {
          "id": "3ffe496f-2a36-4e5a-a749-6f51dbbe8aee",
          "name": "Idempotency Conflict — Step 2 (409)",
          "request": {
            "name": "Create a payment intent",
            "description": {
              "content": "Creates a new payment intent and returns a Hosted Checkout URL.\nOptionally send `Idempotency-Key` to safely retry without duplicate payments.\n",
              "type": "text/plain"
            },
            "url": {
              "path": [
                "v1",
                "payment-intents"
              ],
              "host": [
                "{{baseUrl}}"
              ],
              "query": [],
              "variable": [],
              "raw": "{{baseUrl}}/v1/payment-intents"
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "postman-conflict-demo-key",
                "type": "text"
              }
            ],
            "method": "POST",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"amount\": 999,\n  \"currency\": \"EGP\",\n  \"externalOrderId\": \"CONFLICT-DEMO\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('Status code is 201', function () { pm.response.to.have.status(201); });",
                  "const json = pm.response.json();",
                  "pm.test('Success envelope with paymentId', function () {",
                  "  pm.expect(json.success).to.eql(true);",
                  "  pm.expect(json.data).to.have.property('paymentId');",
                  "  pm.expect(json.data).to.have.property('checkoutUrl');",
                  "});",
                  "const jsonCreate = pm.response.json();",
                  "if (jsonCreate.data) {",
                  "  pm.environment.set('paymentId', jsonCreate.data.paymentId);",
                  "  pm.environment.set('checkoutUrl', jsonCreate.data.checkoutUrl);",
                  "  if (jsonCreate.data.expiresAt) pm.environment.set('expiresAt', jsonCreate.data.expiresAt);",
                  "  const parts = String(jsonCreate.data.checkoutUrl || '').split('/');",
                  "  pm.environment.set('checkoutToken', parts[parts.length - 1] || '');",
                  "}",
                  "pm.test('Response time under 5000ms', function () {",
                  "  pm.expect(pm.response.responseTime).to.be.below(5000);",
                  "});",
                  "const requestId = pm.response.headers.get('X-Request-ID');",
                  "if (requestId) { pm.environment.set('requestId', requestId); }",
                  "pm.test('Status code is 409', function () { pm.response.to.have.status(409); });",
                  "const json = pm.response.json();",
                  "pm.test('Idempotency conflict envelope', function () {",
                  "  pm.expect(json.success).to.eql(false);",
                  "  pm.expect(json.error.code).to.eql('IDEMPOTENCY_CONFLICT');",
                  "  pm.expect(json.error.type).to.eql('idempotency_error');",
                  "});"
                ]
              }
            }
          ],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        }
      ],
      "description": "Intentional error scenarios using the unified Public API error contract."
    },
    {
      "name": "Examples",
      "item": [
        {
          "id": "3ffe496f-2a36-4e5a-a749-6f51dbbe8aee",
          "name": "1. Create a payment intent",
          "request": {
            "name": "Create a payment intent",
            "description": {
              "content": "Creates a new payment intent and returns a Hosted Checkout URL.\nOptionally send `Idempotency-Key` to safely retry without duplicate payments.\n",
              "type": "text/plain"
            },
            "url": {
              "path": [
                "v1",
                "payment-intents"
              ],
              "host": [
                "{{baseUrl}}"
              ],
              "query": [],
              "variable": [],
              "raw": "{{baseUrl}}/v1/payment-intents"
            },
            "header": [
              {
                "disabled": true,
                "description": "Optional idempotency key. Same key + same body replays the stored response.",
                "key": "Idempotency-Key",
                "value": "{{idempotencyKey}}"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "POST",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"amount\": 150,\n  \"customerPhone\": \"+201012345678\",\n  \"externalOrderId\": \"ORD-123\",\n  \"currency\": \"EGP\",\n  \"successUrl\": \"https://merchant.com/checkout/success\",\n  \"cancelUrl\": \"https://merchant.com/checkout/cancel\",\n  \"redirectDelay\": 5,\n  \"metadata\": {\n    \"description\": \"Order 123\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('Status code is 201', function () { pm.response.to.have.status(201); });",
                  "const json = pm.response.json();",
                  "pm.test('Success envelope with paymentId', function () {",
                  "  pm.expect(json.success).to.eql(true);",
                  "  pm.expect(json.data).to.have.property('paymentId');",
                  "  pm.expect(json.data).to.have.property('checkoutUrl');",
                  "});",
                  "const jsonCreate = pm.response.json();",
                  "if (jsonCreate.data) {",
                  "  pm.environment.set('paymentId', jsonCreate.data.paymentId);",
                  "  pm.environment.set('checkoutUrl', jsonCreate.data.checkoutUrl);",
                  "  if (jsonCreate.data.expiresAt) pm.environment.set('expiresAt', jsonCreate.data.expiresAt);",
                  "  const parts = String(jsonCreate.data.checkoutUrl || '').split('/');",
                  "  pm.environment.set('checkoutToken', parts[parts.length - 1] || '');",
                  "}",
                  "pm.test('Response time under 5000ms', function () {",
                  "  pm.expect(pm.response.responseTime).to.be.below(5000);",
                  "});",
                  "const requestId = pm.response.headers.get('X-Request-ID');",
                  "if (requestId) { pm.environment.set('requestId', requestId); }"
                ]
              }
            }
          ],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        },
        {
          "id": "a84c87c5-abac-4e85-8147-eb4419a57c22",
          "name": "2. Get payment intent",
          "request": {
            "name": "Get payment intent",
            "description": {
              "content": "Returns the payment intent when it exists in the same environment as the API key.\nCross-environment access (test key on a live payment, or vice versa) returns **404**\nwith `RESOURCE_NOT_FOUND` to avoid resource enumeration (DISC-008).\n",
              "type": "text/plain"
            },
            "url": {
              "path": [
                "v1",
                "payment-intents",
                "{{paymentId}}"
              ],
              "host": [
                "{{baseUrl}}"
              ],
              "query": [],
              "variable": [
                {
                  "disabled": false,
                  "type": "any",
                  "value": "{{paymentId}}",
                  "key": "paymentId",
                  "description": "(Required) "
                }
              ],
              "raw": "{{baseUrl}}/v1/payment-intents/{{paymentId}}"
            },
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('Status code is 200', function () { pm.response.to.have.status(200); });",
                  "const json = pm.response.json();",
                  "pm.test('Payment intent returned', function () {",
                  "  pm.expect(json.success).to.eql(true);",
                  "  pm.expect(json.data.paymentId).to.eql(pm.environment.get('paymentId'));",
                  "});",
                  "pm.test('Response time under 5000ms', function () {",
                  "  pm.expect(pm.response.responseTime).to.be.below(5000);",
                  "});",
                  "const requestId = pm.response.headers.get('X-Request-ID');",
                  "if (requestId) { pm.environment.set('requestId', requestId); }"
                ]
              }
            }
          ],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        },
        {
          "id": "61bec12d-4556-4a14-bd74-d42b58ec3836",
          "name": "3. Get lightweight payment status",
          "request": {
            "name": "Get lightweight payment status",
            "description": {
              "content": "Polling-friendly status DTO with six fields only.\nCross-environment access returns **404** with `RESOURCE_NOT_FOUND` (DISC-008).\n",
              "type": "text/plain"
            },
            "url": {
              "path": [
                "v1",
                "payment-intents",
                "{{paymentId}}",
                "status"
              ],
              "host": [
                "{{baseUrl}}"
              ],
              "query": [],
              "variable": [
                {
                  "disabled": false,
                  "type": "any",
                  "value": "{{paymentId}}",
                  "key": "paymentId",
                  "description": "(Required) "
                }
              ],
              "raw": "{{baseUrl}}/v1/payment-intents/{{paymentId}}/status"
            },
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "GET"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('Status code is 200', function () { pm.response.to.have.status(200); });",
                  "const json = pm.response.json();",
                  "pm.test('Status DTO shape', function () {",
                  "  pm.expect(json.success).to.eql(true);",
                  "  pm.expect(json.data).to.have.keys('paymentId', 'status', 'matchStatus', 'verificationStatus', 'paidAt', 'updatedAt');",
                  "});",
                  "pm.test('API-Version header is v1', function () {",
                  "  pm.expect(pm.response.headers.get('API-Version')).to.eql('v1');",
                  "});",
                  "pm.test('Deprecation header is false', function () {",
                  "  pm.expect(pm.response.headers.get('Deprecation')).to.eql('false');",
                  "});",
                  "pm.test('Response time under 5000ms', function () {",
                  "  pm.expect(pm.response.responseTime).to.be.below(5000);",
                  "});",
                  "const requestId = pm.response.headers.get('X-Request-ID');",
                  "if (requestId) { pm.environment.set('requestId', requestId); }"
                ]
              }
            }
          ],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        },
        {
          "id": "234db5d3-8247-47aa-a1b2-7a7673125cf8",
          "name": "4. Cancel a pending payment intent",
          "request": {
            "name": "Cancel a pending payment intent",
            "description": {
              "content": "Cancels a pending payment intent in the same environment as the API key.\nCross-environment access returns **404** with `RESOURCE_NOT_FOUND` (DISC-008).\n",
              "type": "text/plain"
            },
            "url": {
              "path": [
                "v1",
                "payment-intents",
                "{{paymentId}}",
                "cancel"
              ],
              "host": [
                "{{baseUrl}}"
              ],
              "query": [],
              "variable": [
                {
                  "disabled": false,
                  "type": "any",
                  "value": "{{paymentId}}",
                  "key": "paymentId",
                  "description": "(Required) "
                }
              ],
              "raw": "{{baseUrl}}/v1/payment-intents/{{paymentId}}/cancel"
            },
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "method": "POST"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('Status code is 200', function () { pm.response.to.have.status(200); });",
                  "const json = pm.response.json();",
                  "pm.test('Cancelled payment intent', function () {",
                  "  pm.expect(json.success).to.eql(true);",
                  "  pm.expect(json.data.status).to.eql('cancelled');",
                  "});",
                  "pm.test('Response time under 5000ms', function () {",
                  "  pm.expect(pm.response.responseTime).to.be.below(5000);",
                  "});",
                  "const requestId = pm.response.headers.get('X-Request-ID');",
                  "if (requestId) { pm.environment.set('requestId', requestId); }"
                ]
              }
            }
          ],
          "protocolProfileBehavior": {
            "disableBodyPruning": true
          }
        }
      ],
      "description": "End-to-end flow: Create → Get → Status → Cancel. Run in order; variables chain automatically."
    }
  ],
  "event": [
    {
      "listen": "prerequest",
      "script": {
        "type": "text/javascript",
        "exec": [
          "const key = pm.variables.replaceIn('{{$guid}}');",
          "pm.variables.set('idempotencyKey', key);",
          "pm.variables.set('timestamp', new Date().toISOString());"
        ]
      }
    }
  ],
  "variable": [
    {
      "key": "baseUrl",
      "value": "https://api.bsyncapp.com"
    },
    {
      "key": "apiKey",
      "value": ""
    },
    {
      "key": "paymentId",
      "value": ""
    },
    {
      "key": "checkoutUrl",
      "value": ""
    },
    {
      "key": "checkoutToken",
      "value": ""
    },
    {
      "key": "idempotencyKey",
      "value": ""
    },
    {
      "key": "expiresAt",
      "value": ""
    },
    {
      "key": "requestId",
      "value": ""
    },
    {
      "key": "webhookUrl",
      "value": "https://webhook.site/your-endpoint"
    },
    {
      "key": "timestamp",
      "value": ""
    }
  ],
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{apiKey}}",
        "type": "string"
      }
    ]
  },
  "info": {
    "_postman_id": "86cf19c6-fcc2-4f33-9477-656b99ec1863",
    "name": "BSync Public API",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
    "description": "Official BSync Public Developer API collection — generated from `openapi/openapi.yaml`.\n\nInteractive docs: https://api.bsyncapp.com/docs\nSpec: https://api.bsyncapp.com/openapi.yaml\n\nImport a Test or Live environment, set `apiKey`, then run the **Examples** folder."
  }
}
