{
  "openapi": "3.0.3",
  "info": {
    "title": "Snap Pay Merchant API",
    "version": "1.0.0",
    "description": "Payouts to mobile money in Kenya and Uganda, rates, number checks and transaction status. Docs: https://snapcashpay.com/developers"
  },
  "servers": [
    {
      "url": "https://uat.snapcashpay.com/api/v1",
      "description": "Sandbox (test money, sk_test_ keys)"
    },
    {
      "url": "https://snapcashpay.com/api/v1",
      "description": "Live (real money, sk_live_ keys)"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Account"
    },
    {
      "name": "Payouts"
    },
    {
      "name": "Transactions"
    },
    {
      "name": "Sandbox"
    }
  ],
  "paths": {
    "/balance": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Balance",
        "operationId": "getBalance",
        "responses": {
          "200": {
            "description": "Balance",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Balance"
                },
                "example": {
                  "currency": "KES",
                  "balance_minor": 1250000,
                  "balance": "12500.00"
                }
              }
            }
          },
          "401": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "unauthenticated",
                  "message": "Invalid, replaced or inactive API key."
                }
              }
            }
          },
          "429": {
            "description": "Too many requests (see Retry-After)"
          }
        }
      }
    },
    "/rates": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Indicative payout rate",
        "operationId": "getRate",
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "KES"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "UGX"
            }
          },
          {
            "name": "amount",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number",
              "example": 1000
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Quote",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Rate"
                },
                "example": {
                  "from": "KES",
                  "to": "UGX",
                  "rate": 27.85,
                  "indicative": true,
                  "note": "The rate is applied when the payout is made and is not locked by this quote.",
                  "quoted_at": "2026-10-29T10:15:02+03:00",
                  "amount": "1000.00",
                  "converted_amount": "27850.00"
                }
              }
            }
          },
          "422": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "rate_unavailable",
                  "message": "No rate is available for KES to XYZ right now."
                }
              }
            }
          },
          "401": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "unauthenticated",
                  "message": "Invalid, replaced or inactive API key."
                }
              }
            }
          },
          "429": {
            "description": "Too many requests (see Retry-After)"
          }
        }
      }
    },
    "/accounts/lookup": {
      "post": {
        "tags": [
          "Payouts"
        ],
        "summary": "Check a mobile money number",
        "operationId": "lookupAccount",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LookupRequest"
              },
              "example": {
                "phone": "256772123456",
                "country": "UG",
                "network": "mtn"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LookupResult"
                },
                "example": {
                  "valid": true,
                  "name": "JANE NAKATO",
                  "name_available": true,
                  "phone": "256772123456",
                  "country": "UG"
                }
              }
            }
          },
          "403": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "payouts_not_enabled",
                  "message": "Payouts through the API are not enabled for your account. Contact Snap Pay to enable them."
                }
              }
            }
          },
          "422": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "lookup_unavailable",
                  "message": "The number could not be checked on that network right now."
                }
              }
            }
          },
          "401": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "unauthenticated",
                  "message": "Invalid, replaced or inactive API key."
                }
              }
            }
          },
          "429": {
            "description": "Too many requests (see Retry-After)"
          }
        }
      }
    },
    "/payouts": {
      "post": {
        "tags": [
          "Payouts"
        ],
        "summary": "Create a payout",
        "operationId": "createPayout",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{8,64}$"
            },
            "description": "Unique per payout; reuse to retry safely."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PayoutRequest"
              },
              "example": {
                "amount": 1500,
                "currency": "KES",
                "recipient_phone": "254712345678",
                "recipient_name": "John Kamau",
                "recipient_country": "KE",
                "network": "mpesa",
                "narration": "October commission",
                "client_reference": "INV-10293"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Payout accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Payout"
                },
                "example": {
                  "object": "payout",
                  "reference": "SNP-7K2M9QXA",
                  "client_reference": "INV-10293",
                  "status": "processing",
                  "amount": "1500.00",
                  "currency": "KES",
                  "destination_amount": "1500.00",
                  "destination_currency": "KES",
                  "fx_rate": 1,
                  "fee": "0.00",
                  "recipient": {
                    "name": "John Kamau",
                    "phone": "254712345678",
                    "country": "KE",
                    "network": "mpesa"
                  },
                  "narration": "October commission",
                  "created_at": "2026-10-29T10:16:40+03:00",
                  "updated_at": "2026-10-29T10:16:41+03:00"
                }
              }
            }
          },
          "200": {
            "description": "Replay of an earlier request with the same Idempotency-Key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Payout"
                }
              }
            }
          },
          "400": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "idempotency_key_required",
                  "message": "Send an Idempotency-Key header (8-64 letters, digits, - or _), unique per payout."
                }
              }
            }
          },
          "403": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "payouts_not_enabled",
                  "message": "Payouts through the API are not enabled for your account. Contact Snap Pay to enable them."
                }
              }
            }
          },
          "409": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "idempotency_conflict",
                  "message": "This Idempotency-Key was already used for a different payout."
                }
              }
            }
          },
          "422": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "payout_refused",
                  "message": "Insufficient balance for this payout (scheduled payments are held back)."
                }
              }
            }
          },
          "502": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "payout_error",
                  "message": "The payout could not be started. Nothing was sent; you can retry with the same Idempotency-Key."
                }
              }
            }
          },
          "401": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "unauthenticated",
                  "message": "Invalid, replaced or inactive API key."
                }
              }
            }
          },
          "429": {
            "description": "Too many requests (see Retry-After)"
          }
        }
      },
      "get": {
        "tags": [
          "Payouts"
        ],
        "summary": "List payouts",
        "operationId": "listPayouts",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "processing",
                "succeeded",
                "failed",
                "reversed"
              ]
            }
          },
          {
            "name": "client_reference",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "per_page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Payouts",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayoutList"
                },
                "example": {
                  "data": [
                    {
                      "object": "payout",
                      "reference": "SNP-7K2M9QXA",
                      "client_reference": "INV-10293",
                      "status": "succeeded",
                      "amount": "1500.00",
                      "currency": "KES",
                      "destination_amount": "1500.00",
                      "destination_currency": "KES",
                      "fx_rate": 1,
                      "fee": "0.00",
                      "recipient": {
                        "name": "John Kamau",
                        "phone": "254712345678",
                        "country": "KE",
                        "network": "mpesa"
                      },
                      "narration": "October commission",
                      "created_at": "2026-10-29T10:16:40+03:00",
                      "updated_at": "2026-10-29T10:16:41+03:00"
                    }
                  ],
                  "meta": {
                    "current_page": 1,
                    "last_page": 1,
                    "total": 1
                  }
                }
              }
            }
          },
          "401": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "unauthenticated",
                  "message": "Invalid, replaced or inactive API key."
                }
              }
            }
          },
          "429": {
            "description": "Too many requests (see Retry-After)"
          }
        }
      }
    },
    "/payouts/{reference}": {
      "get": {
        "tags": [
          "Payouts"
        ],
        "summary": "Get a payout",
        "operationId": "getPayout",
        "parameters": [
          {
            "name": "reference",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Payout",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Payout"
                },
                "example": {
                  "object": "payout",
                  "reference": "SNP-7K2M9QXA",
                  "client_reference": "INV-10293",
                  "status": "succeeded",
                  "amount": "1500.00",
                  "currency": "KES",
                  "destination_amount": "1500.00",
                  "destination_currency": "KES",
                  "fx_rate": 1,
                  "fee": "0.00",
                  "recipient": {
                    "name": "John Kamau",
                    "phone": "254712345678",
                    "country": "KE",
                    "network": "mpesa"
                  },
                  "narration": "October commission",
                  "created_at": "2026-10-29T10:16:40+03:00",
                  "updated_at": "2026-10-29T10:16:41+03:00"
                }
              }
            }
          },
          "404": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "not_found",
                  "message": "Payout not found."
                }
              }
            }
          },
          "401": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "unauthenticated",
                  "message": "Invalid, replaced or inactive API key."
                }
              }
            }
          },
          "429": {
            "description": "Too many requests (see Retry-After)"
          }
        }
      }
    },
    "/transactions": {
      "get": {
        "tags": [
          "Transactions"
        ],
        "summary": "List transactions",
        "operationId": "listTransactions",
        "parameters": [
          {
            "name": "per_page",
            "in": "query",
            "schema": {
              "type": "integer",
              "maximum": 100,
              "default": 25
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Transactions",
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "reference": "SNP-4QH2W8LD",
                      "status": "settled",
                      "amount": "2500.00",
                      "currency": "KES",
                      "fee_minor": 3750,
                      "buyer_phone": "254722000111",
                      "payment_link": "SNAP-PL-8DK2LQ0Z",
                      "created_at": "2026-10-28T16:02:11+03:00"
                    }
                  ],
                  "meta": {
                    "current_page": 1,
                    "last_page": 1,
                    "total": 1
                  }
                }
              }
            }
          },
          "401": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "unauthenticated",
                  "message": "Invalid, replaced or inactive API key."
                }
              }
            }
          },
          "429": {
            "description": "Too many requests (see Retry-After)"
          }
        }
      }
    },
    "/payments/{reference}": {
      "get": {
        "tags": [
          "Transactions"
        ],
        "summary": "Payment status",
        "operationId": "getPayment",
        "parameters": [
          {
            "name": "reference",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Transaction",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Transaction"
                },
                "example": {
                  "reference": "SNP-4QH2W8LD",
                  "status": "settled",
                  "amount": "2500.00",
                  "currency": "KES",
                  "fee_minor": 3750,
                  "buyer_phone": "254722000111",
                  "payment_link": "SNAP-PL-8DK2LQ0Z",
                  "created_at": "2026-10-28T16:02:11+03:00"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "example": {
                  "error": "Payment not found"
                }
              }
            }
          },
          "401": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "unauthenticated",
                  "message": "Invalid, replaced or inactive API key."
                }
              }
            }
          },
          "429": {
            "description": "Too many requests (see Retry-After)"
          }
        }
      }
    },
    "/sandbox/payouts/{reference}/simulate": {
      "post": {
        "tags": [
          "Sandbox"
        ],
        "summary": "Simulate a payout outcome (sandbox only)",
        "operationId": "simulatePayout",
        "servers": [
          {
            "url": "https://uat.snapcashpay.com/api/v1"
          }
        ],
        "parameters": [
          {
            "name": "reference",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "outcome"
                ],
                "properties": {
                  "outcome": {
                    "type": "string",
                    "enum": [
                      "succeeded",
                      "failed"
                    ]
                  }
                }
              },
              "example": {
                "outcome": "succeeded"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated payout",
            "content": {
              "application/json": {
                "example": {
                  "object": "payout",
                  "reference": "SNP-7K2M9QXA",
                  "client_reference": "INV-10293",
                  "status": "succeeded",
                  "amount": "1500.00",
                  "currency": "KES",
                  "destination_amount": "1500.00",
                  "destination_currency": "KES",
                  "fx_rate": 1,
                  "fee": "0.00",
                  "recipient": {
                    "name": "John Kamau",
                    "phone": "254712345678",
                    "country": "KE",
                    "network": "mpesa"
                  },
                  "narration": "October commission",
                  "created_at": "2026-10-29T10:16:40+03:00",
                  "updated_at": "2026-10-29T10:16:41+03:00",
                  "webhook_delivery": "sent"
                }
              }
            }
          },
          "409": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "already_final",
                  "message": "This payout already has its final status."
                }
              }
            }
          },
          "401": {
            "description": "Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "unauthenticated",
                  "message": "Invalid, replaced or inactive API key."
                }
              }
            }
          },
          "429": {
            "description": "Too many requests (see Retry-After)"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "sk_test_ (sandbox) or sk_live_ (live) key"
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "details": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        }
      },
      "Balance": {
        "type": "object",
        "properties": {
          "currency": {
            "type": "string"
          },
          "balance_minor": {
            "type": "integer"
          },
          "balance": {
            "type": "string"
          }
        }
      },
      "Rate": {
        "type": "object",
        "properties": {
          "from": {
            "type": "string"
          },
          "to": {
            "type": "string"
          },
          "rate": {
            "type": "number"
          },
          "indicative": {
            "type": "boolean"
          },
          "note": {
            "type": "string"
          },
          "quoted_at": {
            "type": "string",
            "format": "date-time"
          },
          "amount": {
            "type": "string"
          },
          "converted_amount": {
            "type": "string"
          }
        }
      },
      "LookupRequest": {
        "type": "object",
        "required": [
          "phone",
          "country"
        ],
        "properties": {
          "phone": {
            "type": "string"
          },
          "country": {
            "type": "string",
            "enum": [
              "KE",
              "UG"
            ]
          },
          "network": {
            "type": "string",
            "enum": [
              "mpesa",
              "mtn",
              "airtel"
            ]
          }
        }
      },
      "LookupResult": {
        "type": "object",
        "properties": {
          "valid": {
            "type": "boolean"
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "name_available": {
            "type": "boolean"
          },
          "phone": {
            "type": "string"
          },
          "country": {
            "type": "string"
          }
        }
      },
      "PayoutRequest": {
        "type": "object",
        "required": [
          "amount",
          "recipient_phone",
          "recipient_name",
          "recipient_country"
        ],
        "properties": {
          "amount": {
            "type": "number",
            "minimum": 1
          },
          "currency": {
            "type": "string",
            "enum": [
              "KES",
              "UGX"
            ]
          },
          "recipient_phone": {
            "type": "string"
          },
          "recipient_name": {
            "type": "string",
            "maxLength": 128
          },
          "recipient_country": {
            "type": "string",
            "enum": [
              "KE",
              "UG"
            ]
          },
          "network": {
            "type": "string",
            "enum": [
              "mpesa",
              "mtn",
              "airtel"
            ]
          },
          "narration": {
            "type": "string",
            "maxLength": 140
          },
          "client_reference": {
            "type": "string",
            "maxLength": 64
          }
        }
      },
      "Payout": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "enum": [
              "payout"
            ]
          },
          "reference": {
            "type": "string"
          },
          "client_reference": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "string",
            "enum": [
              "processing",
              "succeeded",
              "failed",
              "reversed"
            ]
          },
          "amount": {
            "type": "string"
          },
          "currency": {
            "type": "string"
          },
          "destination_amount": {
            "type": "string"
          },
          "destination_currency": {
            "type": "string"
          },
          "fx_rate": {
            "type": "number",
            "nullable": true
          },
          "fee": {
            "type": "string"
          },
          "recipient": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "phone": {
                "type": "string"
              },
              "country": {
                "type": "string"
              },
              "network": {
                "type": "string",
                "nullable": true
              }
            }
          },
          "narration": {
            "type": "string",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "PayoutList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Payout"
            }
          },
          "meta": {
            "type": "object"
          }
        }
      },
      "Transaction": {
        "type": "object",
        "properties": {
          "reference": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "amount": {
            "type": "string"
          },
          "currency": {
            "type": "string"
          },
          "fee_minor": {
            "type": "integer"
          },
          "buyer_phone": {
            "type": "string",
            "nullable": true
          },
          "payment_link": {
            "type": "string",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "WebhookEvent": {
        "type": "object",
        "description": "POSTed to your webhook URL. Verify X-Snap-Signature = 'sha256=' + hex HMAC-SHA256(raw body, webhook secret).",
        "properties": {
          "event": {
            "type": "string",
            "enum": [
              "payout.succeeded",
              "payout.failed",
              "payout.reversed"
            ]
          },
          "event_id": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "data": {
            "$ref": "#/components/schemas/Payout"
          }
        }
      }
    }
  }
}