{
  "info": {
    "name": "TachoPay Partner API",
    "description": "B2B partner API for mobile recharge & bill payment.\n\nBase URL: `https://api.tachopay.com/v1/partner`\n\nAuth: Bearer `tpk_test_*` (sandbox) or `tpk_live_*` (production).\n\nTwo-step bill payment: bill-info → pay-bill → transaction status.\n\nSandbox phone-suffix outcomes:\n- `…0001` SUCCESS\n- `…0002` FAILED + refund\n- `…0003` SUCCESS after 30s\n- `…0004` FAILED after 30s\n- `…0005` stuck PENDING",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      { "key": "token", "value": "{{api_key}}", "type": "string" }
    ]
  },
  "variable": [
    { "key": "base_url", "value": "https://api.tachopay.com/v1/partner" },
    { "key": "api_key", "value": "tpk_test_REPLACE_ME" }
  ],
  "item": [
    {
      "name": "1. Get balance",
      "request": {
        "method": "GET",
        "url": "{{base_url}}/balance",
        "description": "Returns prepaid wallet balance in the partner's corridor currency."
      }
    },
    {
      "name": "2. List operators",
      "request": {
        "method": "GET",
        "url": "{{base_url}}/operators",
        "description": "List all mobile operators in the partner's corridor."
      }
    },
    {
      "name": "3. Mobile prepaid recharge",
      "request": {
        "method": "POST",
        "header": [
          { "key": "Content-Type", "value": "application/json" },
          { "key": "Idempotency-Key", "value": "{{$guid}}", "description": "Unique per request — Postman auto-generates" }
        ],
        "url": "{{base_url}}/topup",
        "body": {
          "mode": "raw",
          "raw": "{\n  \"operator_id\": 14,\n  \"phone\": \"8801712340001\",\n  \"amount\": 100,\n  \"reference\": \"my-internal-ref-1\"\n}"
        },
        "description": "Send a mobile prepaid recharge.\n\n- Returns optimistic `PENDING` in <500ms.\n- Wallet is debited immediately; the response shows `balance_after`.\n- Final outcome via webhook OR `GET /transactions/:order_id`.\n- Sandbox: phone ending …0001 = SUCCESS, …0002 = FAILED+refund."
      }
    },
    {
      "name": "4. Bill payment — Step 1: fetch bill",
      "request": {
        "method": "POST",
        "header": [{ "key": "Content-Type", "value": "application/json" }],
        "url": "{{base_url}}/bill-info",
        "body": {
          "mode": "raw",
          "raw": "{\n  \"biller_id\": 14,\n  \"consumer_number\": \"9876543210001\"\n}"
        },
        "description": "Step 1 of two-step bill payment.\n\nFetches the outstanding amount, customer name, and due date from the biller.\nUse the returned `amount` exactly in Step 2.\n\nSandbox consumer_number suffix outcomes:\n- …0001 → 500.00\n- …0002 → 1500.00\n- …0003 → 850.50\n- …0004 → 2400.00 (overdue)\n- …0099 → 0.00 (no dues)"
      }
    },
    {
      "name": "5. Bill payment — Step 2: pay bill",
      "request": {
        "method": "POST",
        "header": [
          { "key": "Content-Type", "value": "application/json" },
          { "key": "Idempotency-Key", "value": "{{$guid}}" }
        ],
        "url": "{{base_url}}/pay-bill",
        "body": {
          "mode": "raw",
          "raw": "{\n  \"biller_id\": 14,\n  \"consumer_number\": \"9876543210001\",\n  \"amount\": 500.00,\n  \"reference\": \"bill-jun-2026\"\n}"
        },
        "description": "Step 2 of two-step bill payment.\n\nSubmit the bill payment with the EXACT amount returned by `/bill-info`.\nAmount must match within ±1 unit, otherwise `amount_mismatch` error.\n\nSame lifecycle as `/topup` — PENDING immediately, settles async."
      }
    },
    {
      "name": "6. Check transaction status",
      "request": {
        "method": "GET",
        "url": "{{base_url}}/transactions/TP202600119",
        "description": "Poll for the final status of a transaction.\n\nReturns:\n- `PENDING` — still in flight (poll again or wait for webhook)\n- `SUCCESS` — includes `operator_ref` (and `settled_at`)\n- `FAILED` — includes `refunded_at` (money returned to wallet)\n\nReplace TP202600119 with the order_id from your topup/pay-bill response."
      }
    },
    {
      "name": "7. Idempotent retry (proof — replay safe)",
      "request": {
        "method": "POST",
        "header": [
          { "key": "Content-Type", "value": "application/json" },
          { "key": "Idempotency-Key", "value": "demo-idempotency-key-001" }
        ],
        "url": "{{base_url}}/topup",
        "body": {
          "mode": "raw",
          "raw": "{\n  \"operator_id\": 14,\n  \"phone\": \"8801712340001\",\n  \"amount\": 100\n}"
        },
        "description": "Send this request, then SEND IT AGAIN.\n\nThe response is identical (replay-safe). The wallet is debited only once.\nThe response includes header `Idempotent-Replay: true` on the replay.\n\nWithin 24h of first call, same Idempotency-Key + same body = same response.\nDifferent body = 409 conflict."
      }
    }
  ]
}
