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

# Charge an ugwo

> Run a charge activity against a payment request.

Creates an activity on the ugwo. The activity describes one attempt
to act on the payment; today the only supported type is `charge`,
which sends the ugwo to a PSP through the medium you specify.

Activities are independent: a single ugwo can host many of them. If
a `mobile_money` charge fails, you can immediately create a
`bank_transfer` activity on the same ugwo without recreating it.

<Note>
  The ugwo must have a resolved checkout before you can create an
  activity against it. If the ugwo's `checkout` is `null` (no
  checkout was supplied at creation and the workspace couldn't route
  one), this endpoint returns `422`.
</Note>

## Path parameters

<ParamField path="ugwoUid" type="string" required>
  The ugwo to charge, `ugw.XXXX.YYYY...`.
</ParamField>

## Body parameters

<ParamField body="type" type="string" required>
  The activity type. Currently only `charge` is supported.
</ParamField>

<ParamField body="data" type="object" required>
  Type-specific payload. `data.medium` selects the payment medium,
  and the rest of the keys inside `data` are the parameters for that
  medium (see [Medium parameters](#medium-parameters) below).
</ParamField>

### Medium parameters

`data.medium` is one of `bank_transfer`, `ussd`, or `mobile_money`.
The other keys inside `data` depend on which one you picked.

<Tabs>
  <Tab title="bank_transfer">
    ```json theme={null}
    {
      "type": "charge",
      "data": {
        "medium": "bank_transfer",
        "expires_at": "2026-05-15T10:30:00+00:00"
      }
    }
    ```

    <ParamField body="expires_at" type="string">
      ISO-8601 (`DATE_ATOM`) timestamp for when the virtual account
      should stop accepting transfers. Optional; defaults to **15
      minutes from now**. Must be in the future and **no more than
      15 minutes ahead**; timestamps in the past or further out
      than 15 minutes return `422`.
    </ParamField>

    Available for **Nigeria (NGN)**.
  </Tab>

  <Tab title="ussd">
    ```json theme={null}
    {
      "type": "charge",
      "data": {
        "medium": "ussd",
        "provider": "gtb"
      }
    }
    ```

    <ParamField body="provider" type="string" required>
      Bank code. Pass the text code from the [supported banks
      table](/concepts#ussd-banks-nigeria), e.g. `gtb`. Unknown
      codes return `422`.
    </ParamField>

    Available for **Nigeria (NGN)**.
  </Tab>

  <Tab title="mobile_money">
    <Note>Coming soon with Ghana (GHS) support. See [Concepts](/concepts#countries-and-currencies).</Note>

    Expected shape:

    ```json theme={null}
    {
      "type": "charge",
      "data": {
        "medium": "mobile_money",
        "provider": "mtn",
        "phone": "+233201234567"
      }
    }
    ```
  </Tab>
</Tabs>

## Response

<ResponseField name="uid" type="string">Activity ID (`act.…`).</ResponseField>
<ResponseField name="activity_type" type="string">Always `charge` for this endpoint.</ResponseField>

<ResponseField name="status" type="string">
  Initial activity status. `requires_action` when the customer has
  more to do (bank transfer, USSD), `processing` when handed off to
  the PSP without further customer input, or `failed` on a
  synchronous error.
</ResponseField>

<ResponseField name="checkout" type="object | null">
  Snapshot of the checkout this activity was routed through. Includes
  `uid`, the `currency` as `[code, label]`, and the configured
  `mediums`.
</ResponseField>

<ResponseField name="ugwo_medium" type="object | null">
  Tokenised medium (e.g. a stored card or wallet) the activity used;
  `null` for one-off mediums like `bank_transfer`.
</ResponseField>

<ResponseField name="psp" type="string">
  The PSP that handled the charge, e.g. `paystack_ng`.
</ResponseField>

<ResponseField name="psp_external_id" type="string | null">
  The reference the PSP issued for this attempt. Useful when
  cross-referencing in your PSP dashboard.
</ResponseField>

<ResponseField name="next_action" type="object | null">
  What the customer needs to do next, if anything. See
  [`next_action` shape](#next_action-shape).
</ResponseField>

<ResponseField name="error" type="object | null">
  Populated when the activity failed synchronously.
</ResponseField>

<ResponseField name="created_at" type="string">ISO-8601 timestamp.</ResponseField>
<ResponseField name="updated_at" type="string">ISO-8601 timestamp.</ResponseField>

### `next_action` shape

For `bank_transfer`, `next_action.type` is `user_action` and the
`headers` block carries everything the customer needs to complete
the transfer (account number, bank name, expiry, amount).

```json theme={null}
{
  "type": "user_action",
  "instruction": "Transfer to bank",
  "headers": {
    "bank_name": "Test Bank",
    "expires_at": "2026-05-14T20:10:50+00:00",
    "account_name": "PAYSTACK CHECKOUT",
    "account_number": "1260881821"
  }
}
```

<RequestExample>
  ```bash cURL theme={null}
  curl https://api.kwugwo.africa/v1/ugwo/ugw.VCvr.qnbBJaElzSTHOcaTzxbuDlIs/activities \
    -H "Authorization: Bearer $KWUGWO_SECRET_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "type": "charge",
      "data": {
        "medium": "bank_transfer",
        "expires_at": "2026-05-15T10:30:00+00:00"
      }
    }'
  ```

  ```js Node theme={null}
  const res = await fetch(
    `https://api.kwugwo.africa/v1/ugwo/${ugwoUid}/activities`,
    {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.KWUGWO_SECRET_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        type: "charge",
        data: { medium: "bank_transfer" },
      }),
    }
  );
  const activity = await res.json();
  ```

  ```php PHP theme={null}
  <?php
  $ch = curl_init("https://api.kwugwo.africa/v1/ugwo/{$ugwoUid}/activities");
  curl_setopt_array($ch, [
      CURLOPT_RETURNTRANSFER => true,
      CURLOPT_POST           => true,
      CURLOPT_HTTPHEADER     => [
          'Authorization: Bearer ' . getenv('KWUGWO_SECRET_KEY'),
          'Content-Type: application/json',
      ],
      CURLOPT_POSTFIELDS => json_encode([
          'type' => 'charge',
          'data' => ['medium' => 'bank_transfer'],
      ]),
  ]);
  $activity = json_decode(curl_exec($ch), true);
  curl_close($ch);
  ```

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

  activity = requests.post(
      f"https://api.kwugwo.africa/v1/ugwo/{ugwo_uid}/activities",
      headers={"Authorization": f"Bearer {os.environ['KWUGWO_SECRET_KEY']}"},
      json={
          "type": "charge",
          "data": {"medium": "bank_transfer"},
      },
  ).json()
  ```

  ```go Go theme={null}
  package main

  import (
      "bytes"
      "encoding/json"
      "fmt"
      "io"
      "net/http"
      "os"
  )

  func main() {
      body, _ := json.Marshal(map[string]any{
          "type": "charge",
          "data": map[string]any{"medium": "bank_transfer"},
      })

      url := fmt.Sprintf("https://api.kwugwo.africa/v1/ugwo/%s/activities", ugwoUid)
      req, _ := http.NewRequest("POST", url, bytes.NewReader(body))
      req.Header.Set("Authorization", "Bearer "+os.Getenv("KWUGWO_SECRET_KEY"))
      req.Header.Set("Content-Type", "application/json")

      resp, _ := http.DefaultClient.Do(req)
      defer resp.Body.Close()
      out, _ := io.ReadAll(resp.Body)
      fmt.Println(string(out))
  }
  ```
</RequestExample>

<ResponseExample>
  ```json 200 OK (bank_transfer) theme={null}
  {
    "uid": "act.VCvr.qnbBJaElzSTHOcaTzxbuDlIs",
    "activity_type": "charge",
    "checkout": {
      "uid": "chk.VCvr.vBtGwathtd99FpQGIGwIAATX",
      "currency": ["NGN", "Nigerian Naira (NGN)"],
      "mediums": [
        { "medium": "bank_transfer" },
        { "medium": "ussd" }
      ]
    },
    "ugwo_medium": null,
    "psp": "paystack_ng",
    "psp_external_id": "5kfxw34ugz",
    "next_action": {
      "type": "user_action",
      "instruction": "Transfer to bank",
      "headers": {
        "bank_name": "Test Bank",
        "expires_at": "2026-05-14T20:10:50+00:00",
        "account_name": "PAYSTACK CHECKOUT",
        "account_number": "1260881821"
      }
    },
    "status": "requires_action",
    "created_at": "2026-05-14T19:55:50+00:00",
    "error": null,
    "updated_at": "2026-05-14T19:55:51+00:00"
  }
  ```

  ```json 200 OK (ussd) theme={null}
  {
    "uid": "act.VCvr.w9qTsfJMQkBIaITiGRDucv1u",
    "activity_type": "charge",
    "checkout": {
      "uid": "chk.VCvr.vBtGwathtd99FpQGIGwIAATX",
      "currency": ["NGN", "Nigerian Naira (NGN)"],
      "mediums": [
        { "medium": "bank_transfer" },
        { "medium": "ussd" }
      ]
    },
    "ugwo_medium": null,
    "psp": "paystack_ng",
    "psp_external_id": "s09v485jla6ckt1",
    "next_action": {
      "type": "user_action",
      "instruction": "Please dial *737*33*4*92811# on your mobile phone to complete the transaction",
      "headers": {
        "ussd": "*737*33*4*92811#"
      }
    },
    "status": "requires_action",
    "created_at": "2026-05-15T16:10:18+00:00",
    "error": null,
    "updated_at": "2026-05-15T16:10:18+00:00"
  }
  ```

  ```json 422 Validation Failed theme={null}
  {
    "title": "Validation Failed",
    "status": 422,
    "violations": [
      { "propertyPath": "provider", "title": "This value should not be blank." }
    ]
  }
  ```
</ResponseExample>
