---
url: /api/get-request.md
---
# Get a Request

Returns the current state of a request you raised. Use it when:

* you did not give a `callbackURL`, or
* your callback server was down for a long time and you want to catch up, or
* you just want to double-check before acting.

## Endpoint

| Method | URL |
|---|---|
| `GET` | `/api/requests/:requestID` |

| Path parameter | Description |
|---|---|
| `requestID` | The `requestID` you got when you [created the request](/api/create-request), or from a callback |

```
<timestamp>.GET./api/requests/6650f1a2b3c4d5e6f7a8b9e1.
```

You can only see requests raised with **your** API key. That includes [child requests](/guide/statuses#partial-payments) made from them.

## Response

`data` is the request summary. It has the same fields as a [callback](/guide/callbacks#what-we-send), in the same order, without `event`, `deliveryID` and `changedAt`:

| Field | Type | Description |
|---|---|---|
| `requestID` | `string` | The request's ID |
| `requestNumber` | `string` | Its number in Johari |
| `status` | `string` | Current status. See [Request Statuses](/guide/statuses) |
| `statusTitle` | `string` | Status as people see it in Johari, e.g. `"Pending Payment"` |
| `description` | `string` | What the payment is for |
| `amount` | `number` | The request amount |
| `currency` | `string` | e.g. `"TZS"` |
| `amountRemaining` | `number \| null` | Only for a request being paid in parts: how much is still unpaid. Otherwise `null` |
| `modeOfPayment` | `string` | `"cash"` or `"bank"` |
| `isUrgent` | `boolean` | `true` if the request is marked urgent |
| `company` | `object` | The requesting company: `{ "id": string, "name": string }` |
| `site` | `object` | The requesting site: `{ "id": string, "name": string }` |
| `costCode` | `string` | The cost code `value` |
| `isChildRequest` | `boolean` | `true` for one part of a request being paid in parts. See [Partial payments](/guide/statuses#partial-payments) |
| `mainRequestID` | `string \| null` | For a child request, the request it belongs to. Otherwise `null` |
| `note` | `string \| null` | Only the note written with the **latest** status change, e.g. the rejection reason, the return reason, a payment note or an approval comment. `null` if that change had no note. Never an older note |
| `createdAt` | `string` | When the request was created (ISO 8601, UTC) |
| `createdBy` | `string` | Name of the person in Johari who created it. For requests you raise, the API key's user's name followed by ` (API)`, e.g. `"Neema Mollel (API)"`. Johari shows the same in the request, its log and the WhatsApp notifications, so people can see a system raised it |
| `approvedAt` | `string \| null` | When it was approved (ISO 8601, UTC) |
| `approvedBy` | `string \| null` | Name of the person who approved it. If the request was approved automatically (because the key's user may approve it themselves), it is also the key's user's name followed by ` (API)` |
| `rejectedAt` | `string \| null` | When it was rejected (ISO 8601, UTC) |
| `rejectedBy` | `string \| null` | Name of the person who rejected it |
| `confirmedAt` | `string \| null` | When accounts confirmed it, sending it for payment (ISO 8601, UTC) |
| `confirmedBy` | `string \| null` | Name of the person who confirmed it |
| `paidAt` | `string \| null` | When it was paid (ISO 8601, UTC) |
| `paidBy` | `string \| null` | Name of the person who paid it |
| `efdAt` | `string \| null` | When the EFD (tax) receipt was uploaded (ISO 8601, UTC) |
| `efdBy` | `string \| null` | Name of the person who uploaded the EFD receipt |
| `returnedAt` | `string \| null` | When it was returned (ISO 8601, UTC) |
| `returnedBy` | `string \| null` | Name of the person who returned it |
| `returnedTo` | `string \| null` | Who the cashier returned it to: `"creator"`, `"approver"` or `"confirmer"`. `null` if it was never returned. While `status` is `"returned"` and this is `"creator"`, the request is waiting for **your** system to answer. Keeps its last value after the request moves on, so always check `status` too. See [Returned requests](#returned-requests) |
| `files` | `array` | Every file on the request. See [Files](#files) |

The `...At` fields say when that step happened. The `...By` fields are the name of the person in Johari who did it. Each one is `null` until that step happens.

`note` is only ever the note from the latest status change. Johari's other internal notes are not shared.

### Returned requests

`returnedTo` says who the cashier returned the request to.

* While `status` is `"returned"` and `returnedTo` is `"creator"`, the request is waiting for **your** system to answer. See [Respond to a Return](/api/respond-to-return).
* When it is `"approver"` or `"confirmer"`, that person answers it in Johari. You just receive the callbacks.

`returnedTo` keeps its last value after the request moves on, so always check `status` too. See [Returned](/guide/statuses#returned).

### Files

`files` lists every file on the request:

* the files sent when the request was [created](/api/create-request#attaching-files),
* the proof of payment the cashier uploads when paying,
* the EFD receipt,
* any file people attach to the request in Johari (for example an accountant's upload),
* any file your system adds with [Add Files](/api/add-files).

Each item:

| Field | Type | Description |
|---|---|---|
| `id` | `string` | The file's ID. Use it with [Get a File](/api/get-file) to download it |
| `name` | `string` | The file name, e.g. `"invoice-1042.pdf"` |
| `type` | `string \| null` | The file type, e.g. `"application/pdf"`, or `null` |
| `size` | `number \| null` | The size in bytes, or `null` |

There is no download link in `files`. Ask [Get a File](/api/get-file) for a fresh link each time you need one. Internal storage paths are never shown.

## Example

::: code-group

```bash [cURL]
REQUEST_ID="6650f1a2b3c4d5e6f7a8b9e1"
TS=$(date +%s)
SIG=$(printf '%s' "$TS.GET./api/requests/$REQUEST_ID." \
  | openssl dgst -sha256 -hmac "$SIGNING_SECRET" \
  | sed 's/^.* //')
curl "$BASE_URL/api/requests/$REQUEST_ID" \
  -H "x-api-key: $API_KEY" \
  -H "x-timestamp: $TS" \
  -H "x-signature: $SIG"
```

```js [Node.js]
const requestID = "6650f1a2b3c4d5e6f7a8b9e1";
const result = await callJohari("GET", `/api/requests/${requestID}`);
console.log(result.data.status);
```

```python [Python]
request_id = "6650f1a2b3c4d5e6f7a8b9e1"
result = call_johari("GET", f"/api/requests/{request_id}")
print(result["data"]["status"])
```

:::

Response `200`, for a request that has been paid and completed:

```json
{
  "status": "success",
  "data": {
    "requestID": "6650f1a2b3c4d5e6f7a8b9e1",
    "requestNumber": "1042",
    "status": "completed",
    "statusTitle": "Completed",
    "description": "Cement for slab",
    "amount": 150000,
    "currency": "TZS",
    "amountRemaining": null,
    "modeOfPayment": "bank",
    "isUrgent": false,
    "company": {
      "id": "6650f1a2b3c4d5e6f7a8b901",
      "name": "Example Construction Ltd"
    },
    "site": {
      "id": "3c9a7f52-1d4e-4b8a-9f6c-2e1d5a7b8c90",
      "name": "Block A Apartments"
    },
    "costCode": "1003",
    "isChildRequest": false,
    "mainRequestID": null,
    "note": null,
    "createdAt": "2026-10-29T09:58:04.112Z",
    "createdBy": "Neema Mollel (API)",
    "approvedAt": "2026-10-29T10:12:36.571Z",
    "approvedBy": "Amina Juma",
    "rejectedAt": null,
    "rejectedBy": null,
    "confirmedAt": "2026-10-29T13:40:18.230Z",
    "confirmedBy": "Grace Kimaro",
    "paidAt": "2026-10-30T07:55:02.918Z",
    "paidBy": "Joseph Mwakyusa",
    "efdAt": "2026-10-30T11:20:45.067Z",
    "efdBy": "Joseph Mwakyusa",
    "returnedAt": null,
    "returnedBy": null,
    "returnedTo": null,
    "files": [
      {
        "id": "0b6f2c1e-8d4a-4f3b-9e7c-5a1d2b3c4e5f",
        "name": "invoice-1042.pdf",
        "type": "application/pdf",
        "size": 48213
      },
      {
        "id": "5e9a1b7c-3d2f-4a6e-8b1c-9d0e2f3a4b5c",
        "name": "payment-slip-1042.pdf",
        "type": "application/pdf",
        "size": 102944
      },
      {
        "id": "a2c4e6f8-1b3d-4f5a-9c7e-0d2b4f6a8c1e",
        "name": "efd-receipt-1042.jpg",
        "type": "image/jpeg",
        "size": 231570
      }
    ]
  },
  "message": "Request fetched successfully"
}
```

Response `404`:

```json
{
  "status": "error",
  "data": null,
  "message": "Request not found"
}
```

You get `404` when the ID is wrong, when the request was raised with a different API key, or when it was deleted in Johari. If the request has a `callbackURL`, a deletion also sends a [`request.deleted` callback](/guide/callbacks#events).

## Polling

If you rely on this endpoint instead of callbacks, do not call it in a tight loop. Requests move at human speed: checking each open request every **5 to 15 minutes** is plenty. Stop checking once the status is final (`completed`, `rejected` or `master-partial-payment-completed`), or once you get `404` because the request was deleted.

## Related pages

* [Get a File](/api/get-file)
* [Respond to a Return](/api/respond-to-return)
* [Add Files](/api/add-files)
* [Callbacks](/guide/callbacks)
* [Request Statuses](/guide/statuses)
