# Answer a question

Answer a question a run is waiting on. The answer is checked against the wait’s schema, recorded, and handed to the step that asked, and the turn continues.

`POST https://api.momor.ai/workflow/runs/{runId}/waits/{waitId}`

The run’s owner answers: the signed-in person or the API key that started the run. The `waitId` comes from the `wait.<class>.raised` event on the run’s stream, which also carries the question and the schema the answer must match.

## Path

- `runId` (uuid, required): The run holding the wait.
- `waitId` (uuid, required): The wait, from its wait.<class>.raised event.

## Body

The answer itself, as JSON. What it may be depends on the wait.

| Wait | Answer |
| --- | --- |
| `Clarification` | A JSON string, or { "Declined": true, "Reason": "…" } to say no. |
| `UserLocationRequired` | A JSON string naming the place. |
| `Signal` | Any JSON. |

## Responses

| Status | Body |
| --- | --- |
| `204` | The answer was recorded. The turn continues once every wait it is holding is answered. |

With `Accept: text/event-stream`, the response follows the run’s current turn to its end instead: an `opened` frame, the turn’s events, then `closed`.

## Errors

| Status | Code | What happened |
| --- | --- | --- |
| `401` | `—` | No API key or session. |
| `404` | `—` | You hold no run with this id, or the run holds no wait with this id. |
| `409` | `—` | The wait is already answered. |
| `410` | `—` | The wait ended before this answer arrived: its turn was cancelled, superseded, replaced or timed out. |
| `422` | `—` | The answer does not match the wait’s schema. The wait stays open. |

```bash title="Request"
curl -X POST "https://api.momor.ai/workflow/runs/$RUN_ID/waits/$WAIT_ID" \
  -H "Authorization: Bearer $MOMOR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '"Approved. The photos show the damage."'
```

```python
import os, requests

requests.post(
    f"https://api.momor.ai/workflow/runs/{run_id}/waits/{wait_id}",
    headers={"Authorization": f"Bearer {os.environ['MOMOR_API_KEY']}"},
    json={"Declined": True, "Reason": "Outside the return window."},
)
```

```typescript
await fetch(`https://api.momor.ai/workflow/runs/${runId}/waits/${waitId}`, {
    method: 'POST',
    headers: {
        Authorization: `Bearer ${process.env.MOMOR_API_KEY}`,
        'Content-Type': 'application/json',
    },
    body: JSON.stringify('Approved. The photos show the damage.'),
});
```

```csharp
using var http = new HttpClient { BaseAddress = new Uri("https://api.momor.ai") };
http.DefaultRequestHeaders.Authorization = new("Bearer", Environment.GetEnvironmentVariable("MOMOR_API_KEY"));

var response = await http.PostAsJsonAsync(
    $"/workflow/runs/{runId}/waits/{waitId}",
    "Approved. The photos show the damage.");
```

```json title="The question, as the stream sent it"
{
  "event": "wait.intervention.raised",
  "path": "…",
  "waitId": "5c0e2f71-94ab-4d3e-8b16-7a2d9e4c0f58",
  "payload": {
    "waitId": "5c0e2f71-94ab-4d3e-8b16-7a2d9e4c0f58",
    "class": "intervention",
    "invocationId": "…",
    "canonicalCallId": "…",
    "name": "Clarification",
    "question": "This refund is over $500. Approve it?",
    "resolutionSchema": {
      "oneOf": [
        { "type": "string" },
        {
          "type": "object",
          "required": ["Declined"],
          "properties": { "Declined": { "const": true }, "Reason": { "type": "string" } }
        }
      ]
    },
    "raisedAt": "2026-10-22T09:14:00Z",
    "timeoutAt": null
  }
}
```
