{
  "info": {
    "name": "Zoorya Pay API — Sandbox",
    "description": "Every Zoorya Pay request, ready to send against the **sandbox**. Full guide: https://developer.zooryapay.et/resources/postman\n\n**1. Fill in the collection variables** (click the collection → **Variables**):\n\n| Variable | Where it comes from |\n|---|---|\n| `apiKey` | Merchant portal → Developer → API keys. Paste the **whole** key, `zp-checkout-…:…`. It is split into `apiKeyId` (identity) and `apiKeySecret` (password) for you |\n| `organisationId` | Merchant portal → avatar menu → Profile → Company |\n| `walletId` | Merchant portal → avatar menu → Profile → Company → Wallet ID |\n| `hmacKey` | For payment links. Create one at https://developer.zooryapay.et/api-reference/c2b-direct/payment-link#create-an-hmackey |\n| `callbackUrl` | Where webhooks go, e.g. your ngrok address (optional) |\n| `mpesaPhone`, `phone` | A phone **you** control, 9-digit form: `712345678`, `912345678` |\n| `zemenAccount` | A Zemen Bank account you control (10–20 digits) |\n\n**2. Send any request.** The collection logs in for you with `apiKey` when it has no token or the token has expired (about 15 minutes), and fills in `tenantId`.\n\n**3. Follow a payment:** `2. Checkout` → open `completionUrl` from the Console and pay → `5. After payment` → Get a payment. Deliver only when `status` is `SUCCESSFUL`.\n\n**Rules**\n- Sandbox moves test money, but every prompt and SMS is **real** — use a phone or account you control.\n- `externalUniqueId` must be new for every payment. The collection makes a new one before each request.\n- Keep `apiKey`, the token and `hmacKey` secret. Never put a production key in a shared workspace.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{token}}",
        "type": "string"
      }
    ]
  },
  "event": [
    {
      "listen": "prerequest",
      "script": {
        "type": "text/javascript",
        "exec": [
          "const v = pm.collectionVariables;",
          "",
          "// You fill in only apiKey: the whole key from the merchant portal, \"<key id>:<secret>\".",
          "// It may be a collection, environment or global variable — pm.variables finds it in any of them.",
          "// Log in wants it in two parts, so split it here: apiKeyId = before the first colon (identity),",
          "// apiKeySecret = the rest (password). Saved as variables, so Postman's Code view shows the real request.",
          "// The collection's own value wins, so an old apiKey left in an environment can't override the key you pasted.",
          "const apiKey = String(v.get('apiKey') || pm.variables.get('apiKey') || '').trim();",
          "const colon = apiKey.indexOf(':');",
          "if (colon > 0) {",
          "  v.set('apiKeyId', apiKey.slice(0, colon));",
          "  v.set('apiKeySecret', apiKey.slice(colon + 1));",
          "} else if (apiKey) {",
          "  throw new Error('apiKey must be the whole key from the merchant portal, with the colon: zp-checkout-…:…');",
          "}",
          "// No apiKey: Log in still goes out with whatever is in its body, so typing identity and password there works too.",
          "",
          "// Log in automatically when there is no token or it is about to expire, so any request can be sent first.",
          "// A login call never needs this, whatever the request is named: recognise it by its URL.",
          "const isLogin = /\\/authentication\\/login\\/?$/.test(pm.request.url.getPath());",
          "// A missing or unreadable expiry counts as expired, so an old token is never reused by mistake.",
          "const expiresAt = Number(v.get('tokenExpires'));",
          "const expired = !v.get('token') || !(expiresAt > Date.now() + 60 * 1000);",
          "if (!isLogin && expired) {",
          "  if (!apiKey) throw new Error('Not logged in: set the collection variable apiKey to your whole API key (zp-checkout-…:…), or run 1. Log in first.');",
          "  const loginUrl = pm.variables.get('baseUrl') + '/authentication/login';",
          "  pm.sendRequest({",
          "    url: loginUrl,",
          "    method: 'POST',",
          "    header: { 'Content-Type': 'application/json' },",
          "    body: { mode: 'raw', raw: JSON.stringify({ identity: v.get('apiKeyId'), password: v.get('apiKeySecret') }) },",
          "  }, (err, res) => {",
          "    // Shown as a failed test and in the Console: an error thrown here is not always reported.",
          "    const fail = (message) => {",
          "      console.error(message);",
          "      pm.test(message, () => { throw new Error(message); });",
          "      throw new Error(message);",
          "    };",
          "    if (err) fail('Automatic log in could not reach ' + loginUrl + ': ' + err.message);",
          "    if (res.code === 404) fail('Automatic log in: ' + loginUrl + ' was not found (404). baseUrl should be https://sandbox.eclipse.et/eclipse-conductor/rest/v1');",
          "    if (res.code !== 200) fail('Automatic log in failed (' + res.code + '): check apiKey — the whole key, zp-checkout-…:…');",
          "    const b = res.json();",
          "    v.set('token', b.headerValue.replace(/^Bearer /, ''));",
          "    v.set('tenantId', String(b.tenantId));",
          "    v.set('tokenExpires', String(Date.parse(b.expires)));",
          "  });",
          "}"
        ]
      }
    },
    {
      "listen": "test",
      "script": {
        "type": "text/javascript",
        "exec": [
          "// 401 = the token was refused (e.g. \"JWT has expired\"). Forget it, so the next Send logs in again by itself.",
          "if (pm.response.code === 401 && !/\\/authentication\\/login\\/?$/.test(pm.request.url.getPath())) {",
          "  pm.collectionVariables.unset('token');",
          "  pm.collectionVariables.unset('tokenExpires');",
          "  console.warn('The token was refused (401). It has been cleared — click Send again: the collection logs in for you.');",
          "}"
        ]
      }
    }
  ],
  "variable": [
    {
      "key": "baseUrl",
      "value": "https://sandbox.eclipse.et/eclipse-conductor/rest/v1",
      "description": "Sandbox API base URL. Every request is {{baseUrl}}/… — don't add /eclipse-conductor/rest/v1 to the request URLs again."
    },
    {
      "key": "middlewareUrl",
      "value": "https://sandbox.eclipse.et/eclipse-conductor/middleware/api/v1",
      "description": "Base URL of the middleware. Only Zemen Bank → 1. Verify account uses it."
    },
    {
      "key": "apiKey",
      "value": "",
      "type": "secret",
      "description": "Your whole API key from the merchant portal (Developer → API keys), zp-checkout-…:…. Paste it here, or straight into the Log in body."
    },
    {
      "key": "organisationId",
      "value": "",
      "description": "Merchant portal → avatar menu → Profile → Company → Organisation ID."
    },
    {
      "key": "walletId",
      "value": "",
      "description": "Merchant portal → avatar menu → Profile → Company → Wallet ID. The wallet that receives the money."
    },
    {
      "key": "hmacKey",
      "value": "",
      "type": "secret",
      "description": "For payment links. Create one at https://developer.zooryapay.et/api-reference/c2b-direct/payment-link#create-an-hmackey"
    },
    {
      "key": "callbackUrl",
      "value": "https://your-domain.et/webhooks/zoorya",
      "description": "Where Zoorya Pay POSTs the final result of a payment (a public https:// address, e.g. ngrok)."
    },
    {
      "key": "landingUrl",
      "value": "https://your-domain.et/payment-done",
      "description": "Where the payer's browser goes after paying a link."
    },
    {
      "key": "amount",
      "value": "2",
      "description": "Amount in ETB for every payment request."
    },
    {
      "key": "mpesaPhone",
      "value": "7XXXXXXXX",
      "description": "An M-Pesa phone you control, 9-digit form (712345678). A real PIN prompt is sent to it."
    },
    {
      "key": "phone",
      "value": "9XXXXXXXX",
      "description": "A telebirr / bank phone you control, 9-digit form (912345678). A real prompt is sent to it."
    },
    {
      "key": "zemenAccount",
      "value": "",
      "description": "A Zemen Bank account you control (10–20 digits)."
    },
    {
      "key": "zemenOtp",
      "value": "",
      "description": "The SMS code from Zemen Bank → 1. Verify account."
    },
    {
      "key": "apiKeyId",
      "value": "",
      "description": "Filled in for you: the part of apiKey before the first colon (sent as identity)."
    },
    {
      "key": "apiKeySecret",
      "value": "",
      "type": "secret",
      "description": "Filled in for you: the part of apiKey after the first colon (sent as password)."
    },
    {
      "key": "token",
      "value": "",
      "type": "secret",
      "description": "Filled in by Log in. Works for about 15 minutes."
    },
    {
      "key": "tokenExpires",
      "value": "",
      "description": "Filled in by Log in: when the token stops working."
    },
    {
      "key": "tenantId",
      "value": "",
      "description": "Filled in by Log in."
    },
    {
      "key": "externalUniqueId",
      "value": "",
      "description": "Filled in before each payment: a new unique ID every time."
    },
    {
      "key": "paymentId",
      "value": "",
      "description": "Filled in by the last payment request. Used by Get a payment."
    },
    {
      "key": "completionUrl",
      "value": "",
      "description": "Filled in by Create one-time link: the link to open and pay."
    },
    {
      "key": "qrValue",
      "value": "",
      "description": "Filled in by the QR payments: turn it into a QR code to scan."
    }
  ],
  "item": [
    {
      "name": "1. Log in",
      "description": "Optional — every other request logs in for you. Run it to see the login response.",
      "item": [
        {
          "name": "Log in",
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// The body has one field: the whole API key from the merchant portal (\"<key id>:<secret>\").",
                  "// The API wants it in two parts, so it is split here before sending:",
                  "// identity = before the first colon, password = the rest.",
                  "let raw = {};",
                  "try { raw = JSON.parse(pm.variables.replaceIn(pm.request.body.raw || '{}')); } catch (e) {}",
                  "const apiKey = String(raw.apiKey || pm.collectionVariables.get('apiKey') || pm.variables.get('apiKey') || '').trim();",
                  "const colon = apiKey.indexOf(':');",
                  "if (colon <= 0) throw new Error('Paste your whole API key (zp-checkout-…:…) into apiKey in the body, or into the collection variable apiKey.');",
                  "// Remember it, so every other request can log in for you too.",
                  "pm.collectionVariables.set('apiKey', apiKey);",
                  "pm.collectionVariables.set('apiKeyId', apiKey.slice(0, colon));",
                  "pm.collectionVariables.set('apiKeySecret', apiKey.slice(colon + 1));",
                  "pm.request.body.update(JSON.stringify({ identity: apiKey.slice(0, colon), password: apiKey.slice(colon + 1) }, null, 2));"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const b = pm.response.json();",
                  "pm.test('Logged in', () => pm.expect(b.headerValue).to.match(/^Bearer /));",
                  "pm.collectionVariables.set('token', b.headerValue.replace(/^Bearer /, ''));",
                  "pm.collectionVariables.set('tenantId', String(b.tenantId));",
                  "pm.collectionVariables.set('tokenExpires', String(Date.parse(b.expires)));",
                  "console.log('Token valid until', b.expires, '| tenantId', b.tenantId);"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": "{{baseUrl}}/authentication/login",
            "description": "Send your API key and get a token (`headerValue`) and your `tenantId`. The token works for about 15 minutes.\n\n**Paste your API key into the body** — the whole key as the merchant portal shows it, in place of `{{apiKey}}`:\n\n```json\n{ \"apiKey\": \"zp-checkout-11248030:92877cfd…\" }\n```\n\n(Or keep `{{apiKey}}` and fill in the collection variable `apiKey`.) Then click **Send**.\n\nThe API itself wants the key in two parts, so before sending Postman turns it into `{ \"identity\": \"<key id>\", \"password\": \"<secret>\" }` — split at the first colon. The Postman **Console** shows what was really sent. Postman's **Code** button shows the one-field body instead: in your own code, send `identity` and `password` (see the docs page).\n\nDocs: https://developer.zooryapay.et/api-reference/c2b-direct/login",
            "auth": {
              "type": "noauth"
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"apiKey\": \"{{apiKey}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "200",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": "{{baseUrl}}/authentication/login",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"apiKey\": \"{{apiKey}}\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"csrfHeaderName\": \"renew-csrf\",\n  \"csrfToken\": \"aBcD1234EfGh5678…\",\n  \"expires\": \"2026-10-17T20:34:54.399Z\",\n  \"headerName\": \"Authorization\",\n  \"headerValue\": \"Bearer eyJraWQiOiIxIiwiYWxnIjoiUFMyNTYifQ.eyJzdWIiOi…\",\n  \"refreshToken\": \"rEfReSh1234ToKeN…\",\n  \"roles\": [],\n  \"sessionId\": \"sEsSiOn1234Id5678…\",\n  \"tenantId\": 12345678,\n  \"expiresEpochSecs\": 1792269294\n}"
            },
            {
              "name": "401",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": "{{baseUrl}}/authentication/login",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"apiKey\": \"{{apiKey}}\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Unauthorized",
              "code": 401,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "[\n  {\n    \"type\": \"BUSINESS\",\n    \"severity\": \"LOW\",\n    \"code\": \"…\",\n    \"description\": \"…\"\n  }\n]"
            }
          ]
        }
      ]
    },
    {
      "name": "2. Checkout — payment link",
      "description": "Create a one-time link, open `completionUrl` (printed in the Console) and pay with any method. Needs `organisationId`, `walletId` and `hmacKey`.",
      "item": [
        {
          "name": "Create one-time link",
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.collectionVariables.set('externalUniqueId', 'zplink' + Date.now().toString(36));"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const b = pm.response.json();",
                  "pm.test('Payment created (PENDING)', () => pm.expect(b.status).to.eql('PENDING'));",
                  "if (b.paymentId) pm.collectionVariables.set('paymentId', String(b.paymentId));",
                  "if (b.completionUrl) pm.collectionVariables.set('completionUrl', b.completionUrl);",
                  "console.log('Open this link and pay:', b.completionUrl);"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": "{{baseUrl}}/tenants/{{tenantId}}/organisations/{{organisationId}}/payments",
            "description": "Creates a payment link for one order. Send `completionUrl` to the payer — they open it and pay with any method.\n\nDocs: https://developer.zooryapay.et/api-reference/c2b-direct/payment-link",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"amount\": {{amount}},\n  \"currency\": \"ETB\",\n  \"type\": \"GLOBAL_PAYMENT_LINK\",\n  \"externalUniqueId\": \"{{externalUniqueId}}\",\n  \"destinationWalletId\": {{walletId}},\n  \"landingUrl\": \"{{landingUrl}}\",\n  \"additionalFields\": [\n    {\n      \"id\": \"HMACKey\",\n      \"value\": \"{{hmacKey}}\"\n    },\n    {\n      \"id\": \"callbackUrl\",\n      \"value\": \"{{callbackUrl}}\"\n    }\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "200 PENDING",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": "{{baseUrl}}/tenants/{{tenantId}}/organisations/{{organisationId}}/payments",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"amount\": {{amount}},\n  \"currency\": \"ETB\",\n  \"type\": \"GLOBAL_PAYMENT_LINK\",\n  \"externalUniqueId\": \"{{externalUniqueId}}\",\n  \"destinationWalletId\": {{walletId}},\n  \"landingUrl\": \"{{landingUrl}}\",\n  \"additionalFields\": [\n    {\n      \"id\": \"HMACKey\",\n      \"value\": \"{{hmacKey}}\"\n    },\n    {\n      \"id\": \"callbackUrl\",\n      \"value\": \"{{callbackUrl}}\"\n    }\n  ]\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"acceptedCardSchemes\": [],\n  \"acceptedPaymentMechanisms\": [],\n  \"additionalFields\": [\n    {\n      \"id\": \"HMACKey\",\n      \"value\": \"your-hmac-key-from-the-merchant-portal\"\n    },\n    {\n      \"id\": \"callbackUrl\",\n      \"value\": \"https://your-domain.et/webhooks/zoorya\"\n    }\n  ],\n  \"amount\": 150,\n  \"cardPhone\": \"251900000000\",\n  \"completionUrl\": \"https://sandbox.eclipse.et/t/abc12\",\n  \"created\": \"2026-10-17T20:02:11.000Z\",\n  \"currency\": \"ETB\",\n  \"externalUniqueId\": \"zplink0001\",\n  \"extraInfo\": \"PLACEHOLDER\",\n  \"fee\": 0,\n  \"organisationId\": 12345678,\n  \"paymentId\": 4581646,\n  \"paymentInstrumentInfo\": {\n    \"cardPhone\": \"251900000000\"\n  },\n  \"paymentTerminalData\": {},\n  \"paymentType\": \"LINK\",\n  \"phone\": \"251900000000\",\n  \"status\": \"PENDING\",\n  \"tracingContext\": \"00-…-…-03\",\n  \"walletId\": 123456789\n}"
            },
            {
              "name": "400",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": "{{baseUrl}}/tenants/{{tenantId}}/organisations/{{organisationId}}/payments",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"amount\": {{amount}},\n  \"currency\": \"ETB\",\n  \"type\": \"GLOBAL_PAYMENT_LINK\",\n  \"externalUniqueId\": \"{{externalUniqueId}}\",\n  \"destinationWalletId\": {{walletId}},\n  \"landingUrl\": \"{{landingUrl}}\",\n  \"additionalFields\": [\n    {\n      \"id\": \"HMACKey\",\n      \"value\": \"{{hmacKey}}\"\n    },\n    {\n      \"id\": \"callbackUrl\",\n      \"value\": \"{{callbackUrl}}\"\n    }\n  ]\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Bad Request",
              "code": 400,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "[\n  {\n    \"type\": \"BUSINESS\",\n    \"severity\": \"LOW\",\n    \"code\": \"PAY005\",\n    \"description\": \"…\"\n  }\n]"
            }
          ]
        }
      ]
    },
    {
      "name": "3. C2B Direct",
      "description": "Charge the customer directly, without the payment page. Each request sends a **real** prompt or SMS.",
      "item": [
        {
          "name": "M-Pesa",
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.collectionVariables.set('externalUniqueId', 'zpmpesa' + Date.now().toString(36));"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const b = pm.response.json();",
                  "pm.test('Payment created (PENDING)', () => pm.expect(b.status).to.eql('PENDING'));",
                  "if (b.paymentId) pm.collectionVariables.set('paymentId', String(b.paymentId));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": "{{baseUrl}}/tenants/{{tenantId}}/organisations/{{organisationId}}/payments",
            "description": "PIN prompt on the customer's M-Pesa phone (`mpesaPhone`).\n\nDocs: https://developer.zooryapay.et/api-reference/c2b-direct/mpesa",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"amount\": {{amount}},\n  \"currency\": \"ETB\",\n  \"type\": \"MPESA_USSD_TOPUP\",\n  \"externalUniqueId\": \"{{externalUniqueId}}\",\n  \"destinationWalletId\": {{walletId}},\n  \"callbackUrl\": \"{{callbackUrl}}\",\n  \"description\": \"Postman test\",\n  \"additionalFields\": [\n    {\n      \"id\": \"phoneNumber\",\n      \"value\": \"{{mpesaPhone}}\"\n    }\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "200 PENDING",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": "{{baseUrl}}/tenants/{{tenantId}}/organisations/{{organisationId}}/payments",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"amount\": {{amount}},\n  \"currency\": \"ETB\",\n  \"type\": \"MPESA_USSD_TOPUP\",\n  \"externalUniqueId\": \"{{externalUniqueId}}\",\n  \"destinationWalletId\": {{walletId}},\n  \"callbackUrl\": \"{{callbackUrl}}\",\n  \"description\": \"Postman test\",\n  \"additionalFields\": [\n    {\n      \"id\": \"phoneNumber\",\n      \"value\": \"{{mpesaPhone}}\"\n    }\n  ]\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"paymentId\": 4581645,\n  \"status\": \"PENDING\",\n  \"amount\": 2,\n  \"currency\": \"ETB\",\n  \"fee\": 0,\n  \"description\": \"zoorya test\",\n  \"externalUniqueId\": \"zpmpesa0001\",\n  \"organisationId\": 12345678,\n  \"created\": \"2026-10-17T19:56:07.000Z\",\n  \"gatewayTransactionId\": \"ws_CO_1710202622560822751620\",\n  \"phone\": \"712345678\"\n}"
            },
            {
              "name": "400",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": "{{baseUrl}}/tenants/{{tenantId}}/organisations/{{organisationId}}/payments",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"amount\": {{amount}},\n  \"currency\": \"ETB\",\n  \"type\": \"MPESA_USSD_TOPUP\",\n  \"externalUniqueId\": \"{{externalUniqueId}}\",\n  \"destinationWalletId\": {{walletId}},\n  \"callbackUrl\": \"{{callbackUrl}}\",\n  \"description\": \"Postman test\",\n  \"additionalFields\": [\n    {\n      \"id\": \"phoneNumber\",\n      \"value\": \"{{mpesaPhone}}\"\n    }\n  ]\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Bad Request",
              "code": 400,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "[\n  {\n    \"type\": \"BUSINESS\",\n    \"severity\": \"LOW\",\n    \"code\": \"PAY005\",\n    \"description\": \"…\"\n  }\n]"
            }
          ]
        },
        {
          "name": "Dashen Bank",
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.collectionVariables.set('externalUniqueId', 'D' + Date.now().toString(36));"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const b = pm.response.json();",
                  "pm.test('Payment created (PENDING)', () => pm.expect(b.status).to.eql('PENDING'));",
                  "if (b.paymentId) pm.collectionVariables.set('paymentId', String(b.paymentId));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": "{{baseUrl}}/tenants/{{tenantId}}/organisations/{{organisationId}}/payments",
            "description": "Push prompt from Dashen Bank on the customer's phone (`phone`). `externalUniqueId` is at most 10 characters.\n\nDocs: https://developer.zooryapay.et/api-reference/c2b-direct/dashen",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"amount\": {{amount}},\n  \"currency\": \"ETB\",\n  \"type\": \"DASHEN_TOP_UP\",\n  \"externalUniqueId\": \"{{externalUniqueId}}\",\n  \"destinationWalletId\": {{walletId}},\n  \"callbackUrl\": \"{{callbackUrl}}\",\n  \"description\": \"Postman test\",\n  \"additionalFields\": [\n    {\n      \"id\": \"phoneNumber\",\n      \"value\": \"{{phone}}\"\n    }\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "200 PENDING",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": "{{baseUrl}}/tenants/{{tenantId}}/organisations/{{organisationId}}/payments",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"amount\": {{amount}},\n  \"currency\": \"ETB\",\n  \"type\": \"DASHEN_TOP_UP\",\n  \"externalUniqueId\": \"{{externalUniqueId}}\",\n  \"destinationWalletId\": {{walletId}},\n  \"callbackUrl\": \"{{callbackUrl}}\",\n  \"description\": \"Postman test\",\n  \"additionalFields\": [\n    {\n      \"id\": \"phoneNumber\",\n      \"value\": \"{{phone}}\"\n    }\n  ]\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"paymentId\": 4581645,\n  \"status\": \"PENDING\",\n  \"amount\": 2,\n  \"currency\": \"ETB\",\n  \"fee\": 0,\n  \"description\": \"Order 1001\",\n  \"externalUniqueId\": \"D00000001\",\n  \"organisationId\": 12345678,\n  \"created\": \"2026-10-17T19:56:07.000Z\",\n  \"phone\": \"912345678\"\n}"
            },
            {
              "name": "400",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": "{{baseUrl}}/tenants/{{tenantId}}/organisations/{{organisationId}}/payments",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"amount\": {{amount}},\n  \"currency\": \"ETB\",\n  \"type\": \"DASHEN_TOP_UP\",\n  \"externalUniqueId\": \"{{externalUniqueId}}\",\n  \"destinationWalletId\": {{walletId}},\n  \"callbackUrl\": \"{{callbackUrl}}\",\n  \"description\": \"Postman test\",\n  \"additionalFields\": [\n    {\n      \"id\": \"phoneNumber\",\n      \"value\": \"{{phone}}\"\n    }\n  ]\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Bad Request",
              "code": 400,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "[\n  {\n    \"type\": \"BUSINESS\",\n    \"severity\": \"LOW\",\n    \"code\": \"PAY005\",\n    \"description\": \"…\"\n  }\n]"
            }
          ]
        },
        {
          "name": "Nib Bank",
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.collectionVariables.set('externalUniqueId', 'zpnib' + Date.now().toString(36));"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const b = pm.response.json();",
                  "pm.test('Payment created (PENDING)', () => pm.expect(b.status).to.eql('PENDING'));",
                  "if (b.paymentId) pm.collectionVariables.set('paymentId', String(b.paymentId));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": "{{baseUrl}}/tenants/{{tenantId}}/organisations/{{organisationId}}/payments",
            "description": "Push prompt from Nib Bank on the customer's phone (`phone`).\n\nDocs: https://developer.zooryapay.et/api-reference/c2b-direct/nib",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"amount\": {{amount}},\n  \"currency\": \"ETB\",\n  \"type\": \"NIB_TOP_UP\",\n  \"externalUniqueId\": \"{{externalUniqueId}}\",\n  \"destinationWalletId\": {{walletId}},\n  \"callbackUrl\": \"{{callbackUrl}}\",\n  \"description\": \"Postman test\",\n  \"additionalFields\": [\n    {\n      \"id\": \"phoneNumber\",\n      \"value\": \"{{phone}}\"\n    }\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "200 PENDING",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": "{{baseUrl}}/tenants/{{tenantId}}/organisations/{{organisationId}}/payments",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"amount\": {{amount}},\n  \"currency\": \"ETB\",\n  \"type\": \"NIB_TOP_UP\",\n  \"externalUniqueId\": \"{{externalUniqueId}}\",\n  \"destinationWalletId\": {{walletId}},\n  \"callbackUrl\": \"{{callbackUrl}}\",\n  \"description\": \"Postman test\",\n  \"additionalFields\": [\n    {\n      \"id\": \"phoneNumber\",\n      \"value\": \"{{phone}}\"\n    }\n  ]\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"paymentId\": 4581645,\n  \"status\": \"PENDING\",\n  \"amount\": 2,\n  \"currency\": \"ETB\",\n  \"fee\": 0,\n  \"description\": \"Order 1002\",\n  \"externalUniqueId\": \"zpnib0001\",\n  \"organisationId\": 12345678,\n  \"created\": \"2026-10-17T19:56:07.000Z\",\n  \"phone\": \"912345678\"\n}"
            },
            {
              "name": "400",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": "{{baseUrl}}/tenants/{{tenantId}}/organisations/{{organisationId}}/payments",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"amount\": {{amount}},\n  \"currency\": \"ETB\",\n  \"type\": \"NIB_TOP_UP\",\n  \"externalUniqueId\": \"{{externalUniqueId}}\",\n  \"destinationWalletId\": {{walletId}},\n  \"callbackUrl\": \"{{callbackUrl}}\",\n  \"description\": \"Postman test\",\n  \"additionalFields\": [\n    {\n      \"id\": \"phoneNumber\",\n      \"value\": \"{{phone}}\"\n    }\n  ]\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Bad Request",
              "code": 400,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "[\n  {\n    \"type\": \"BUSINESS\",\n    \"severity\": \"LOW\",\n    \"code\": \"PAY005\",\n    \"description\": \"…\"\n  }\n]"
            }
          ]
        },
        {
          "name": "Telebirr",
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.collectionVariables.set('externalUniqueId', 'zptb' + Date.now().toString(36));"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const b = pm.response.json();",
                  "pm.test('Payment created (PENDING)', () => pm.expect(b.status).to.eql('PENDING'));",
                  "if (b.paymentId) pm.collectionVariables.set('paymentId', String(b.paymentId));"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": "{{baseUrl}}/tenants/{{tenantId}}/organisations/{{organisationId}}/payments",
            "description": "PIN prompt on the customer's telebirr phone (`phone`).\n\nDocs: https://developer.zooryapay.et/api-reference/c2b-direct/telebirr",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"amount\": {{amount}},\n  \"currency\": \"ETB\",\n  \"type\": \"ETTA_TELEBIRR_TOP_UP\",\n  \"externalUniqueId\": \"{{externalUniqueId}}\",\n  \"destinationWalletId\": {{walletId}},\n  \"callbackUrl\": \"{{callbackUrl}}\",\n  \"description\": \"Postman test\",\n  \"additionalFields\": [\n    {\n      \"id\": \"phoneNumber\",\n      \"value\": \"{{phone}}\"\n    }\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "200 PENDING",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": "{{baseUrl}}/tenants/{{tenantId}}/organisations/{{organisationId}}/payments",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"amount\": {{amount}},\n  \"currency\": \"ETB\",\n  \"type\": \"ETTA_TELEBIRR_TOP_UP\",\n  \"externalUniqueId\": \"{{externalUniqueId}}\",\n  \"destinationWalletId\": {{walletId}},\n  \"callbackUrl\": \"{{callbackUrl}}\",\n  \"description\": \"Postman test\",\n  \"additionalFields\": [\n    {\n      \"id\": \"phoneNumber\",\n      \"value\": \"{{phone}}\"\n    }\n  ]\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"paymentId\": 4581645,\n  \"status\": \"PENDING\",\n  \"amount\": 2,\n  \"currency\": \"ETB\",\n  \"fee\": 0,\n  \"description\": \"Order 1003\",\n  \"externalUniqueId\": \"zptelebirr0001\",\n  \"organisationId\": 12345678,\n  \"created\": \"2026-10-17T19:56:07.000Z\",\n  \"phone\": \"912345678\"\n}"
            },
            {
              "name": "400",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": "{{baseUrl}}/tenants/{{tenantId}}/organisations/{{organisationId}}/payments",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"amount\": {{amount}},\n  \"currency\": \"ETB\",\n  \"type\": \"ETTA_TELEBIRR_TOP_UP\",\n  \"externalUniqueId\": \"{{externalUniqueId}}\",\n  \"destinationWalletId\": {{walletId}},\n  \"callbackUrl\": \"{{callbackUrl}}\",\n  \"description\": \"Postman test\",\n  \"additionalFields\": [\n    {\n      \"id\": \"phoneNumber\",\n      \"value\": \"{{phone}}\"\n    }\n  ]\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Bad Request",
              "code": 400,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "[\n  {\n    \"type\": \"BUSINESS\",\n    \"severity\": \"LOW\",\n    \"code\": \"PAY005\",\n    \"description\": \"…\"\n  }\n]"
            }
          ]
        },
        {
          "name": "Zemen Bank",
          "description": "Two steps: verify the account (the customer gets an SMS code), then pay with that code.",
          "item": [
            {
              "name": "1. Verify account",
              "event": [
                {
                  "listen": "test",
                  "script": {
                    "type": "text/javascript",
                    "exec": [
                      "pm.test('Account valid', () => pm.expect(pm.response.json().valid).to.eql(true));",
                      "console.log('Put the SMS code in the collection variable zemenOtp, then run 2. Pay with SMS code.');"
                    ]
                  }
                }
              ],
              "request": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": "{{middlewareUrl}}/pay/zemen/payment/validate-customer",
                "description": "Checks the Zemen Bank account (`zemenAccount`). If it is valid, the customer receives an SMS code — put it in `zemenOtp`, then run step 2.\n\nDocs: https://developer.zooryapay.et/api-reference/c2b-direct/zemen-validate",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"accountNumber\": \"{{zemenAccount}}\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "response": [
                {
                  "name": "200",
                  "originalRequest": {
                    "method": "POST",
                    "header": [
                      {
                        "key": "Content-Type",
                        "value": "application/json"
                      }
                    ],
                    "url": "{{middlewareUrl}}/pay/zemen/payment/validate-customer",
                    "body": {
                      "mode": "raw",
                      "raw": "{\n  \"accountNumber\": \"{{zemenAccount}}\"\n}",
                      "options": {
                        "raw": {
                          "language": "json"
                        }
                      }
                    }
                  },
                  "status": "OK",
                  "code": 200,
                  "_postman_previewlanguage": "json",
                  "header": [
                    {
                      "key": "Content-Type",
                      "value": "application/json"
                    }
                  ],
                  "body": "{ \"valid\": true }"
                }
              ]
            },
            {
              "name": "2. Pay with SMS code",
              "event": [
                {
                  "listen": "prerequest",
                  "script": {
                    "type": "text/javascript",
                    "exec": [
                      "pm.collectionVariables.set('externalUniqueId', 'zpzemen' + Date.now().toString(36));"
                    ]
                  }
                },
                {
                  "listen": "test",
                  "script": {
                    "type": "text/javascript",
                    "exec": [
                      "const b = pm.response.json();",
                      "pm.test('Payment created (PENDING)', () => pm.expect(b.status).to.eql('PENDING'));",
                      "if (b.paymentId) pm.collectionVariables.set('paymentId', String(b.paymentId));"
                    ]
                  }
                }
              ],
              "request": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": "{{baseUrl}}/tenants/{{tenantId}}/organisations/{{organisationId}}/payments",
                "description": "Pays from the Zemen Bank account with the SMS code (`zemenOtp`) from step 1.\n\nDocs: https://developer.zooryapay.et/api-reference/c2b-direct/zemen-pay",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"amount\": {{amount}},\n  \"currency\": \"ETB\",\n  \"type\": \"ZEMEN_TOP_UP\",\n  \"externalUniqueId\": \"{{externalUniqueId}}\",\n  \"destinationWalletId\": {{walletId}},\n  \"callbackUrl\": \"{{callbackUrl}}\",\n  \"description\": \"Postman test\",\n  \"additionalFields\": [\n    {\n      \"id\": \"accountNumber\",\n      \"value\": \"{{zemenAccount}}\"\n    },\n    {\n      \"id\": \"otp\",\n      \"value\": \"{{zemenOtp}}\"\n    }\n  ]\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "response": [
                {
                  "name": "200 PENDING",
                  "originalRequest": {
                    "method": "POST",
                    "header": [
                      {
                        "key": "Content-Type",
                        "value": "application/json"
                      }
                    ],
                    "url": "{{baseUrl}}/tenants/{{tenantId}}/organisations/{{organisationId}}/payments",
                    "body": {
                      "mode": "raw",
                      "raw": "{\n  \"amount\": {{amount}},\n  \"currency\": \"ETB\",\n  \"type\": \"ZEMEN_TOP_UP\",\n  \"externalUniqueId\": \"{{externalUniqueId}}\",\n  \"destinationWalletId\": {{walletId}},\n  \"callbackUrl\": \"{{callbackUrl}}\",\n  \"description\": \"Postman test\",\n  \"additionalFields\": [\n    {\n      \"id\": \"accountNumber\",\n      \"value\": \"{{zemenAccount}}\"\n    },\n    {\n      \"id\": \"otp\",\n      \"value\": \"{{zemenOtp}}\"\n    }\n  ]\n}",
                      "options": {
                        "raw": {
                          "language": "json"
                        }
                      }
                    }
                  },
                  "status": "OK",
                  "code": 200,
                  "_postman_previewlanguage": "json",
                  "header": [
                    {
                      "key": "Content-Type",
                      "value": "application/json"
                    }
                  ],
                  "body": "{\n  \"paymentId\": 4581645,\n  \"status\": \"PENDING\",\n  \"amount\": 2,\n  \"currency\": \"ETB\",\n  \"fee\": 0,\n  \"description\": \"Order 1006\",\n  \"externalUniqueId\": \"zpzemen0001\",\n  \"organisationId\": 12345678,\n  \"created\": \"2026-10-17T19:56:07.000Z\"\n}"
                },
                {
                  "name": "400",
                  "originalRequest": {
                    "method": "POST",
                    "header": [
                      {
                        "key": "Content-Type",
                        "value": "application/json"
                      }
                    ],
                    "url": "{{baseUrl}}/tenants/{{tenantId}}/organisations/{{organisationId}}/payments",
                    "body": {
                      "mode": "raw",
                      "raw": "{\n  \"amount\": {{amount}},\n  \"currency\": \"ETB\",\n  \"type\": \"ZEMEN_TOP_UP\",\n  \"externalUniqueId\": \"{{externalUniqueId}}\",\n  \"destinationWalletId\": {{walletId}},\n  \"callbackUrl\": \"{{callbackUrl}}\",\n  \"description\": \"Postman test\",\n  \"additionalFields\": [\n    {\n      \"id\": \"accountNumber\",\n      \"value\": \"{{zemenAccount}}\"\n    },\n    {\n      \"id\": \"otp\",\n      \"value\": \"{{zemenOtp}}\"\n    }\n  ]\n}",
                      "options": {
                        "raw": {
                          "language": "json"
                        }
                      }
                    }
                  },
                  "status": "Bad Request",
                  "code": 400,
                  "_postman_previewlanguage": "json",
                  "header": [
                    {
                      "key": "Content-Type",
                      "value": "application/json"
                    }
                  ],
                  "body": "[\n  {\n    \"type\": \"BUSINESS\",\n    \"severity\": \"LOW\",\n    \"code\": \"PAY005\",\n    \"description\": \"…\"\n  }\n]"
                }
              ]
            }
          ]
        }
      ]
    },
    {
      "name": "4. QR payments",
      "description": "The response has a QR value. Turn it into a QR code and scan it — or use Try it on the docs site, which draws it for you.",
      "item": [
        {
          "name": "Telebirr QR",
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.collectionVariables.set('externalUniqueId', 'zpteleqr' + Date.now().toString(36));"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const b = pm.response.json();",
                  "pm.test('Payment created (PENDING)', () => pm.expect(b.status).to.eql('PENDING'));",
                  "if (b.paymentId) pm.collectionVariables.set('paymentId', String(b.paymentId));",
                  "const qr = (b.additionalFields || []).find((f) => f.id === 'qrUrl');",
                  "if (qr) pm.collectionVariables.set('qrValue', qr.value);",
                  "console.log('Turn this qrUrl into a QR code and scan it:', qr && qr.value);",
                  "console.log('Or use Try it on the docs site: it draws the QR code for you.');"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": "{{baseUrl}}/tenants/{{tenantId}}/organisations/{{organisationId}}/payments",
            "description": "Returns `qrUrl` in `additionalFields`. Scan its QR code with the telebirr app.\n\nDocs: https://developer.zooryapay.et/api-reference/c2b-direct/telebirr-qr",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"amount\": {{amount}},\n  \"currency\": \"ETB\",\n  \"type\": \"TELE_QR_C2B\",\n  \"externalUniqueId\": \"{{externalUniqueId}}\",\n  \"destinationWalletId\": {{walletId}},\n  \"callbackUrl\": \"{{callbackUrl}}\",\n  \"description\": \"Postman test\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "200 PENDING",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": "{{baseUrl}}/tenants/{{tenantId}}/organisations/{{organisationId}}/payments",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"amount\": {{amount}},\n  \"currency\": \"ETB\",\n  \"type\": \"TELE_QR_C2B\",\n  \"externalUniqueId\": \"{{externalUniqueId}}\",\n  \"destinationWalletId\": {{walletId}},\n  \"callbackUrl\": \"{{callbackUrl}}\",\n  \"description\": \"Postman test\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"paymentId\": 4581645,\n  \"status\": \"PENDING\",\n  \"amount\": 2,\n  \"currency\": \"ETB\",\n  \"fee\": 0,\n  \"description\": \"Order 1004\",\n  \"externalUniqueId\": \"zpteleqr0001\",\n  \"organisationId\": 12345678,\n  \"created\": \"2026-10-17T19:56:07.000Z\",\n  \"additionalFields\": [\n    {\n      \"id\": \"qrUrl\",\n      \"value\": \"https://…telebirr…/qr/…\"\n    }\n  ]\n}"
            },
            {
              "name": "400",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": "{{baseUrl}}/tenants/{{tenantId}}/organisations/{{organisationId}}/payments",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"amount\": {{amount}},\n  \"currency\": \"ETB\",\n  \"type\": \"TELE_QR_C2B\",\n  \"externalUniqueId\": \"{{externalUniqueId}}\",\n  \"destinationWalletId\": {{walletId}},\n  \"callbackUrl\": \"{{callbackUrl}}\",\n  \"description\": \"Postman test\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Bad Request",
              "code": 400,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "[\n  {\n    \"type\": \"BUSINESS\",\n    \"severity\": \"LOW\",\n    \"code\": \"PAY005\",\n    \"description\": \"…\"\n  }\n]"
            }
          ]
        },
        {
          "name": "EthSwitch QR",
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.collectionVariables.set('externalUniqueId', 'zpeth' + Date.now().toString(36));"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const b = pm.response.json();",
                  "pm.test('Payment created (PENDING)', () => pm.expect(b.status).to.eql('PENDING'));",
                  "if (b.paymentId) pm.collectionVariables.set('paymentId', String(b.paymentId));",
                  "const qr = (b.additionalFields || []).find((f) => f.id === 'barcode');",
                  "if (qr) pm.collectionVariables.set('qrValue', qr.value);",
                  "console.log('Turn this barcode into a QR code and scan it:', qr && qr.value);",
                  "console.log('Or use Try it on the docs site: it draws the QR code for you.');"
                ]
              }
            }
          ],
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": "{{baseUrl}}/tenants/{{tenantId}}/organisations/{{organisationId}}/payments",
            "description": "Returns `barcode` in `additionalFields`. Scan its QR code with a bank app.\n\nDocs: https://developer.zooryapay.et/api-reference/c2b-direct/ethswitch",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"amount\": {{amount}},\n  \"currency\": \"ETB\",\n  \"type\": \"ETTA_ETH_SWITCH_TOP_UP\",\n  \"externalUniqueId\": \"{{externalUniqueId}}\",\n  \"destinationWalletId\": {{walletId}},\n  \"callbackUrl\": \"{{callbackUrl}}\",\n  \"description\": \"Postman test\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": [
            {
              "name": "200 PENDING",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": "{{baseUrl}}/tenants/{{tenantId}}/organisations/{{organisationId}}/payments",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"amount\": {{amount}},\n  \"currency\": \"ETB\",\n  \"type\": \"ETTA_ETH_SWITCH_TOP_UP\",\n  \"externalUniqueId\": \"{{externalUniqueId}}\",\n  \"destinationWalletId\": {{walletId}},\n  \"callbackUrl\": \"{{callbackUrl}}\",\n  \"description\": \"Postman test\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"paymentId\": 4581645,\n  \"status\": \"PENDING\",\n  \"amount\": 2,\n  \"currency\": \"ETB\",\n  \"fee\": 0,\n  \"description\": \"Order 1005\",\n  \"externalUniqueId\": \"zpethswitch0001\",\n  \"organisationId\": 12345678,\n  \"created\": \"2026-10-17T19:56:07.000Z\",\n  \"additionalFields\": [\n    {\n      \"id\": \"barcode\",\n      \"value\": \"000201010212…\"\n    }\n  ]\n}"
            },
            {
              "name": "400",
              "originalRequest": {
                "method": "POST",
                "header": [
                  {
                    "key": "Content-Type",
                    "value": "application/json"
                  }
                ],
                "url": "{{baseUrl}}/tenants/{{tenantId}}/organisations/{{organisationId}}/payments",
                "body": {
                  "mode": "raw",
                  "raw": "{\n  \"amount\": {{amount}},\n  \"currency\": \"ETB\",\n  \"type\": \"ETTA_ETH_SWITCH_TOP_UP\",\n  \"externalUniqueId\": \"{{externalUniqueId}}\",\n  \"destinationWalletId\": {{walletId}},\n  \"callbackUrl\": \"{{callbackUrl}}\",\n  \"description\": \"Postman test\"\n}",
                  "options": {
                    "raw": {
                      "language": "json"
                    }
                  }
                }
              },
              "status": "Bad Request",
              "code": 400,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "[\n  {\n    \"type\": \"BUSINESS\",\n    \"severity\": \"LOW\",\n    \"code\": \"PAY005\",\n    \"description\": \"…\"\n  }\n]"
            }
          ]
        }
      ]
    },
    {
      "name": "5. After payment",
      "description": "Confirm a payment before you deliver the order.",
      "item": [
        {
          "name": "Get a payment",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const b = pm.response.json();",
                  "console.log('status:', b.status, '| amount:', b.amount);",
                  "pm.test('Status read', () => pm.expect(b.status).to.be.a('string'));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": "{{baseUrl}}/tenants/{{tenantId}}/payments/{{paymentId}}",
            "description": "Reads the payment saved as `paymentId` by the last payment request. Deliver only when `status` is `SUCCESSFUL` and `amount` matches your order.\n\nDocs: https://developer.zooryapay.et/api-reference/c2b-direct/get-payment"
          },
          "response": [
            {
              "name": "200",
              "originalRequest": {
                "method": "GET",
                "header": [],
                "url": "{{baseUrl}}/tenants/{{tenantId}}/payments/{{paymentId}}"
              },
              "status": "OK",
              "code": 200,
              "_postman_previewlanguage": "json",
              "header": [
                {
                  "key": "Content-Type",
                  "value": "application/json"
                }
              ],
              "body": "{\n  \"paymentId\": 4581645,\n  \"status\": \"SUCCESSFUL\",\n  \"amount\": 2,\n  \"currency\": \"ETB\",\n  \"fee\": 0,\n  \"externalUniqueId\": \"zpmpesa0001\",\n  \"gatewayTransactionId\": \"ws_CO_1710202622560822751620\",\n  \"organisationId\": 12345678\n}"
            }
          ]
        }
      ]
    }
  ]
}
