{
  "info": {
    "name": "PamoPay for Business",
    "description": "Take payments from anyone in Tanzania with mobile money. One REST API with a secret key; signed webhooks back to your server. Every failure is a code, documented at https://docs.pamopay.co/errors/<CODE>.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{key}}",
        "type": "string"
      }
    ]
  },
  "variable": [
    {
      "key": "base",
      "value": "https://europe-west1-pamopay-fintech.cloudfunctions.net/merchantSandboxApi",
      "description": "Sandbox. Switch to the live URL to go live."
    },
    {
      "key": "key",
      "value": "sk_test_…",
      "description": "Your test key, from the Developers screen."
    }
  ],
  "item": [
    {
      "name": "Charges",
      "item": [
        {
          "name": "Ask a phone to pay",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base}}/v1/charges",
              "host": [
                "{{base}}"
              ],
              "path": [
                "v1",
                "charges"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"amount_minor\": 4650000,\n  \"rail\": \"mpesa\",\n  \"msisdn\": \"0759280775\",\n  \"reference\": \"ORD-00417\",\n  \"description\": \"2 × kanga, delivery Kariakoo\",\n  \"metadata\": {\n    \"cart_id\": \"c_88a1\"\n  }\n}"
            },
            "description": "The payer receives a network prompt on their handset and approves it with their mobile-money PIN. They have 15 minutes. Wait for `succeeded` by webhook or poll; `processing` means not yet known and is never a failure."
          }
        },
        {
          "name": "List charges",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base}}/v1/charges",
              "host": [
                "{{base}}"
              ],
              "path": [
                "v1",
                "charges"
              ]
            },
            "description": ""
          }
        },
        {
          "name": "One charge",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base}}/v1/charges/:id",
              "host": [
                "{{base}}"
              ],
              "path": [
                "v1",
                "charges",
                ":id"
              ]
            },
            "description": ""
          }
        },
        {
          "name": "A code on the counter",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base}}/v1/pos/charges",
              "host": [
                "{{base}}"
              ],
              "path": [
                "v1",
                "pos",
                "charges"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"till\": \"400291\",\n  \"amount_minor\": 4650000,\n  \"reference\": \"SALE-3391\"\n}"
            },
            "description": "For a till system. Nothing is sent to anybody until the customer scans. The code lives five minutes."
          }
        }
      ]
    },
    {
      "name": "Balance",
      "item": [
        {
          "name": "Your balance",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base}}/v1/balance",
              "host": [
                "{{base}}"
              ],
              "path": [
                "v1",
                "balance"
              ]
            },
            "description": "Read from the ledger, not a cache. The sandbox always answers zero."
          }
        }
      ]
    },
    {
      "name": "Bills",
      "item": [
        {
          "name": "Issue a bill",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base}}/v1/bills",
              "host": [
                "{{base}}"
              ],
              "path": [
                "v1",
                "bills"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"customer_ref\": \"STU-2026-0412\",\n  \"amount_minor\": 25000000,\n  \"payer_name\": \"Neema Kileo\",\n  \"description\": \"Term 3 fees\"\n}"
            },
            "description": "A receivable with a twelve-digit control number a payer types into a mobile-money menu. No Idempotency-Key: a duplicate bill is a second slip you can see and cancel."
          }
        },
        {
          "name": "List bills",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base}}/v1/bills",
              "host": [
                "{{base}}"
              ],
              "path": [
                "v1",
                "bills"
              ]
            },
            "description": ""
          }
        },
        {
          "name": "One bill",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base}}/v1/bills/:id",
              "host": [
                "{{base}}"
              ],
              "path": [
                "v1",
                "bills",
                ":id"
              ]
            },
            "description": ""
          }
        },
        {
          "name": "Text the payer their control number",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base}}/v1/bills/:id/notify",
              "host": [
                "{{base}}"
              ],
              "path": [
                "v1",
                "bills",
                ":id",
                "notify"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"phone\": \"0759280775\"\n}"
            },
            "description": "One SMS with the outstanding amount, the control number and the bill's link. The number is used once and not stored. A refusal is 200 with `sent: false` and a reason, so a loop over four hundred bills sees which went."
          }
        }
      ]
    },
    {
      "name": "Payment links",
      "item": [
        {
          "name": "A price with a URL on it",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base}}/v1/payment_links",
              "host": [
                "{{base}}"
              ],
              "path": [
                "v1",
                "payment_links"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"amount_minor\": 2500000,\n  \"title\": \"Term 3 trip deposit\",\n  \"reference\": \"TRIP-T3\"\n}"
            },
            "description": "No money moves when you create one; every payment against it is an ordinary charge made later by the payer on the hosted page."
          }
        },
        {
          "name": "List payment links",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base}}/v1/payment_links",
              "host": [
                "{{base}}"
              ],
              "path": [
                "v1",
                "payment_links"
              ]
            },
            "description": ""
          }
        },
        {
          "name": "One payment link",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base}}/v1/payment_links/:id",
              "host": [
                "{{base}}"
              ],
              "path": [
                "v1",
                "payment_links",
                ":id"
              ]
            },
            "description": ""
          }
        }
      ]
    },
    {
      "name": "Events",
      "item": [
        {
          "name": "Every event, delivered or not",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base}}/v1/events",
              "host": [
                "{{base}}"
              ],
              "path": [
                "v1",
                "events"
              ]
            },
            "description": "How you catch up after an outage, or before you had an endpoint."
          }
        },
        {
          "name": "One event",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base}}/v1/events/:id",
              "host": [
                "{{base}}"
              ],
              "path": [
                "v1",
                "events",
                ":id"
              ]
            },
            "description": ""
          }
        },
        {
          "name": "Send an event again",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base}}/v1/events/:id/retry",
              "host": [
                "{{base}}"
              ],
              "path": [
                "v1",
                "events",
                ":id",
                "retry"
              ]
            },
            "description": "Allowed when the event is delivered, exhausted or unrouted. The attempt count resets. Nothing is sent by this call; the delivery job picks it up within a minute."
          }
        }
      ]
    },
    {
      "name": "Webhook endpoints",
      "item": [
        {
          "name": "Set where events go",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base}}/v1/webhook_endpoints",
              "host": [
                "{{base}}"
              ],
              "path": [
                "v1",
                "webhook_endpoints"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"url\": \"https://shop.example.co.tz/pamopay/events\"\n}"
            },
            "description": "One address per mode, and the mode is the key's. Setting a new address rotates the signing secret; saving the same address keeps it. The secret is returned here and can be read again on the dashboard."
          }
        },
        {
          "name": "Where events go",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base}}/v1/webhook_endpoints",
              "host": [
                "{{base}}"
              ],
              "path": [
                "v1",
                "webhook_endpoints"
              ]
            },
            "description": "The endpoint for the key's mode, active or not. Never the secret."
          }
        },
        {
          "name": "Stop sending events",
          "request": {
            "method": "DELETE",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base}}/v1/webhook_endpoints/:id",
              "host": [
                "{{base}}"
              ],
              "path": [
                "v1",
                "webhook_endpoints",
                ":id"
              ]
            },
            "description": "Deactivates the endpoint. Events that happen afterwards are recorded as unrouted and readable at GET /v1/events. Never deleted: the delivery history points at it."
          }
        }
      ]
    }
  ]
}