---
url: /api/respond-to-return.md
---
# Respond to a Return

Answers a request that was returned to **you**. It does exactly what a person does when they answer a return in Johari: the request goes back to whoever returned it, with your answer.

Use it when a request you raised has `status: "returned"` and `returnedTo: "creator"`. The callback that tells you it was returned carries both, and its `note` is the reason it was returned. See [Returned](/guide/statuses#returned).

## Endpoint

| Method | URL |
|---|---|
| `POST` | `/api/requests/:requestID/respond-to-return` |

| Path parameter | Description |
|---|---|
| `requestID` | The request's `requestID`, from [Create a Request](/api/create-request) or a callback |

Send the body as JSON with `Content-Type: application/json`, and sign the exact JSON text. The path you sign includes the request ID:

```
<timestamp>.POST./api/requests/6650f1a2b3c4d5e6f7a8b9e1/respond-to-return.<the JSON body>
```

## When you can use it

All three must be true:

* The request was raised with **your** API key. That includes [child requests](/guide/statuses#partial-payments) made from it.
* Its `status` is `"returned"`.
* It was returned to your key's user: `returnedTo` is `"creator"`.

If it was returned to someone else (its approver or confirmer), you get `403`. That person answers it in Johari, and you get the callbacks.

## Body fields

| Field | Type | Required | Description |
|---|---|---|---|
| `idempotencyKey` | `string` | **Yes** | Your unique ID for this response, 1 to 255 characters. A UUID is ideal. Use a new one for each new response, and reuse it only to retry the same response. See [Idempotency](/guide/idempotency) |
| `note` | `string` | **Yes** | Your answer, e.g. `"The stamped invoice is now attached. The amount is correct."`. Not empty, up to 2000 characters |

Any other field is ignored.

## What happens

Exactly what happens when a person answers the return in Johari:

1. The request goes back to the stage it was returned from:
   * **`pending`** (waiting for approval) if an approver returned it before approving it. The approver gets their usual WhatsApp message asking them to approve it.
   * **`pending-payment`** if the cashier returned it before paying it. The cashier gets their usual WhatsApp message.
2. Your `note` is added to the request, shown as written by your key's user with ` (API)` after the name, e.g. `Neema Mollel (API)`.
3. You get a `request.status-changed` [callback](/guide/callbacks) with the new `status` and your note as `note` (if the request has a `callbackURL`). [Get a Request](/api/get-request) shows the same.

::: tip Asked for a document?
Add it first with [Add Files](/api/add-files), then respond.
:::

## Response

`data` on success:

| Field | Type | Description |
|---|---|---|
| `requestID` | `string` | The request's ID |
| `requestNumber` | `string` | Its number in Johari, e.g. `"1042"` |
| `status` | `string` | Where the request went back to: `"pending"` (an approver returned it, it is waiting for approval again) or `"pending-payment"` (the cashier returned it, it is waiting for payment again) |

## Example

The body:

```json
{
  "idempotencyKey": "9f3b2a1c-4d5e-4f6a-8b7c-0d1e2f3a4b5c",
  "note": "The stamped invoice is now attached. The amount is correct."
}
```

::: code-group

```bash [cURL]
REQUEST_ID="6650f1a2b3c4d5e6f7a8b9e1"
BODY=$(cat <<'EOF'
{
  "idempotencyKey": "9f3b2a1c-4d5e-4f6a-8b7c-0d1e2f3a4b5c",
  "note": "The stamped invoice is now attached. The amount is correct."
}
EOF
)
TS=$(date +%s)
SIG=$(printf '%s' "$TS.POST./api/requests/$REQUEST_ID/respond-to-return.$BODY" \
  | openssl dgst -sha256 -hmac "$SIGNING_SECRET" \
  | sed 's/^.* //')
curl -X POST "$BASE_URL/api/requests/$REQUEST_ID/respond-to-return" \
  -H "Content-Type: application/json" \
  -H "x-api-key: $API_KEY" \
  -H "x-timestamp: $TS" \
  -H "x-signature: $SIG" \
  --data-raw "$BODY"
```

```js [Node.js]
const crypto = require("crypto");

const requestID = "6650f1a2b3c4d5e6f7a8b9e1";

// callJohari is from the Signing page
const result = await callJohari("POST", `/api/requests/${requestID}/respond-to-return`, {
  idempotencyKey: crypto.randomUUID(),
  note: "The stamped invoice is now attached. The amount is correct.",
});

if (result.httpStatus === 200) {
  console.log("Request", result.data.requestNumber, "is now", result.data.status);
} else {
  console.error(result.httpStatus, result.message, result.data);
}
```

```python [Python]
import uuid

request_id = "6650f1a2b3c4d5e6f7a8b9e1"

# call_johari is from the Signing page
result = call_johari("POST", f"/api/requests/{request_id}/respond-to-return", {
    "idempotencyKey": str(uuid.uuid4()),
    "note": "The stamped invoice is now attached. The amount is correct.",
})

if result["httpStatus"] == 200:
    print("Request", result["data"]["requestNumber"], "is now", result["data"]["status"])
else:
    print(result["httpStatus"], result["message"], result["data"])
```

:::

Response `200`:

```json
{
  "status": "success",
  "data": {
    "requestID": "6650f1a2b3c4d5e6f7a8b9e1",
    "requestNumber": "1042",
    "status": "pending-payment"
  },
  "message": "Response submitted successfully"
}
```

Response `409`, same `idempotencyKey` sent again after it worked:

```json
{
  "status": "error",
  "data": {
    "requestID": "6650f1a2b3c4d5e6f7a8b9e1",
    "requestNumber": "1042",
    "status": "pending-payment"
  },
  "message": "A request with this idempotencyKey has already been processed"
}
```

Response `403`, the request was returned to someone else:

```json
{
  "status": "error",
  "data": "This request was returned to its confirmer (Amina Juma), so only they can respond to it",
  "message": "This request was returned to its confirmer (Amina Juma), so only they can respond to it"
}
```

Response `400`, the request is not returned (or the return was already answered):

```json
{
  "status": "error",
  "data": "This request is not in returned status",
  "message": "This request is not in returned status"
}
```

Response `404`, wrong ID, or the request was not raised with your key:

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

The usual `401` errors apply too. Every possible error is listed on the [Errors](/guide/errors#respond-to-a-return-errors) page.

## Common mistakes

::: danger Responding to a request returned to someone else
Only answer when `returnedTo` is `"creator"`. When it is `"approver"` or `"confirmer"`, you get `403`: that person answers it in Johari.
:::

::: danger Checking `returnedTo` without `status`
`returnedTo` keeps its last value after the request moves on. Only `status: "returned"` means the request is waiting for an answer now.
:::

::: danger A new idempotencyKey on every retry
Retries must reuse the key. If your first call worked but the answer was lost, a retry with a new key gets `400` (`This request is not in returned status`) instead of the `409` that tells you it worked. If the cashier returned the request again in the meantime, it would even answer the new return with your old note.
:::

::: danger Reusing the key of an earlier response
A request can be returned more than once. Answer each return with a **new** key. An earlier key gets the `409` for the earlier response (same note) or `400` (a different note), and nothing is sent to the cashier.
:::

## Related pages

* [Request Statuses](/guide/statuses#returned)
* [Add Files](/api/add-files)
* [Get a Request](/api/get-request)
* [Callbacks](/guide/callbacks)
* [Idempotency](/guide/idempotency)
