> ## Documentation Index
> Fetch the complete documentation index at: https://developers.kulmipay.com/llms.txt
> Use this file to discover all available pages before exploring further.

# POST /api/v1/payment/collection — Collect a Payment

> Initiate a payment collection via M-Pesa or PesaLink. Returns an invoice ID and JWT signature for tracking payment status.

Use this endpoint to initiate a payment from your customer. You specify the payment method, amount, currency, and customer details. Kulmi Pay creates an invoice, triggers the appropriate payment network, and returns an invoice ID and JWT signature you use to track the transaction status.

**Method:** `POST`\
**URL:** `https://app.kulmipay.com/api/v1/payment/collection/`

## Authentication

Authenticate with a Bearer token **or** by passing your `public_key` in the request body. Do not use both at the same time.

```http theme={null}
Authorization: Bearer <secret_key>
```

## Request

### Required fields

<ParamField body="method" type="string" required>
  Payment method to use. Currently supported values are `M-PESA` and `PESALINK`.
</ParamField>

<ParamField body="currency" type="string" required>
  Transaction currency. One of: `KES`, `USD`, `EUR`, `GBP`. M-Pesa and PesaLink always settle in KES — if you pass a different currency, Kulmi Pay converts the amount using live exchange rates.
</ParamField>

<ParamField body="amount" type="string" required>
  Payment amount as a decimal string, for example `"1500.00"`. For M-Pesa the minimum is KES 10 and the maximum is KES 150,000.
</ParamField>

<ParamField body="api_ref" type="string" required>
  Your unique reference for this payment, up to 140 characters. Store this value — you use it to reconcile transactions on your side.
</ParamField>

### Customer identity

<ParamField body="phone_number" type="string">
  Customer phone number. **Required for M-Pesa.** Use international format, for example `254712345678`.
</ParamField>

<ParamField body="email" type="string">
  Customer email address.
</ParamField>

<ParamField body="first_name" type="string">
  Customer first name.
</ParamField>

<ParamField body="last_name" type="string">
  Customer last name.
</ParamField>

### Authentication alternative

<ParamField body="public_key" type="string">
  Your publishable API key. Use this instead of a Bearer token when calling from a client-side environment. Must match the environment (sandbox keys contain `test`, live keys contain `live`).
</ParamField>

### Fee configuration

<ParamField body="mobile_tarrif" type="string" default="BUSINESS-PAYS">
  Who pays the processing fee for mobile money payments. Either `BUSINESS-PAYS` (fee deducted from your settlement) or `CUSTOMER-PAYS` (fee added to the customer-facing amount).
</ParamField>

<ParamField body="bank_tarrif" type="string" default="BUSINESS-PAYS">
  Who pays the processing fee for PesaLink bank payments. Either `BUSINESS-PAYS` or `CUSTOMER-PAYS`.
</ParamField>

### Wallet routing

<ParamField body="wallet_id" type="string">
  The alias ID of a specific wallet to receive the funds. If omitted, funds settle into your default settlement wallet for the transaction currency.
</ParamField>

<ParamField body="country" type="string">
  Two-letter ISO 3166-1 alpha-2 country code for the customer address.
</ParamField>

<ParamField body="zipcode" type="string">
  Postal or ZIP code for the billing address.
</ParamField>

<ParamField body="city" type="string">
  City for the billing address.
</ParamField>

<ParamField body="state" type="string">
  State or region for the billing address.
</ParamField>

<ParamField body="address" type="string">
  Street address for billing, up to 140 characters.
</ParamField>

## Response

<ResponseField name="invoice" type="object">
  Details of the invoice created for this payment.

  <Expandable title="invoice properties">
    <ResponseField name="invoice.id" type="string">
      The invoice alias ID. Use this value with the [payment status endpoint](/api-reference/payment-status) to poll for updates.
    </ResponseField>

    <ResponseField name="invoice.state" type="string">
      Current state of the invoice. One of `PENDING`, `PROCESSING`, `COMPLETE`, or `FAILED`. For M-Pesa the state is `PENDING` while the customer is entering their PIN.
    </ResponseField>

    <ResponseField name="invoice.value" type="string">
      The total amount charged, including any fees when `CUSTOMER-PAYS` is set.
    </ResponseField>

    <ResponseField name="invoice.provider" type="string">
      The payment method used to process this invoice, for example `M-PESA` or `PESALINK`.
    </ResponseField>

    <ResponseField name="invoice.api_ref" type="string">
      Your reference string as submitted in the request.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="signature" type="string">
  A JWT you use with the [payment status endpoint](/api-reference/payment-status) to authenticate status checks without a server-side secret key. Store it alongside the invoice ID.
</ResponseField>

## Code examples

<CodeGroup>
  ```bash cURL theme={null}
  curl --request POST \
    --url https://app.kulmipay.com/api/v1/payment/collection/ \
    --header 'Authorization: Bearer YOUR_SECRET_KEY' \
    --header 'Content-Type: application/json' \
    --data '{
      "method": "M-PESA",
      "currency": "KES",
      "amount": "1500.00",
      "api_ref": "order_20240416_001",
      "phone_number": "254712345678",
      "first_name": "Jane",
      "last_name": "Doe",
      "mobile_tarrif": "BUSINESS-PAYS"
    }'
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      "https://app.kulmipay.com/api/v1/payment/collection/",
      headers={
          "Authorization": "Bearer YOUR_SECRET_KEY",
          "Content-Type": "application/json",
      },
      json={
          "method": "M-PESA",
          "currency": "KES",
          "amount": "1500.00",
          "api_ref": "order_20240416_001",
          "phone_number": "254712345678",
          "first_name": "Jane",
          "last_name": "Doe",
          "mobile_tarrif": "BUSINESS-PAYS",
      },
  )

  data = response.json()
  invoice_id = data["invoice"]["id"]
  signature = data["signature"]
  ```
</CodeGroup>

## Example response

```json theme={null}
{
  "invoice": {
    "id": "GQ7KZ2XPNM",
    "state": "PENDING",
    "value": "1500.00",
    "currency": "KES",
    "provider": "M-PESA",
    "api_ref": "order_20240416_001",
    "created_at": "2024-04-16T08:23:11.042Z"
  },
  "signature": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
```

<Note>
  For M-Pesa payments, the invoice state starts as `PENDING`. The customer receives an STK push prompt on their phone and must enter their PIN to complete the payment. Poll the [payment status endpoint](/api-reference/payment-status) or use [webhooks](/webhooks/overview) to detect when the state changes to `COMPLETE` or `FAILED`.
</Note>
