## `POST /sop/webhooks/:callback_id`

**Deliver a webhook callback** — POSTs back to a one-shot callback URL generated by the engine when a webhook step starts. The ULID in the path is the credential. Once consumed, the URL is invalidated and subsequent calls return 409.

> **Auth:** No bearer token required. The ULID in the path is the credential — it is single-use and time-limited.

### Path parameters

- `callback_id` (string ULID, required) — One-shot ULID generated by the engine when a webhook step starts. Obtain from the step's `callback_url` field.

### Response

`200 application/json` — Step advanced; instance continues execution.

```json
{
  "received": true,
  "step_id":   "verify-kyc"
}
```

### Errors

| Status | Code | Meaning |
|--------|------|---------|
| 404 | `not_found` | Callback ID does not exist or has expired. |
| 409 | `callback_already_resolved` | This URL was already consumed. |

### Code examples

#### curl

```bash
curl https://api.opensop.dev/sop/webhooks/01HXYZ_CB_TOKEN \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"status":"success","document_id":"DOC-1234"}'
```

#### Node

```js
await fetch(
  `https://api.opensop.dev/sop/webhooks/${callbackId}`,
  {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ status: "success" })
  }
);
```

#### Python

```python
requests.post(
  f"https://api.opensop.dev/sop/webhooks/{callback_id}",
  json={"status": "success"}
)
```

#### Ruby

```ruby
req = Net::HTTP::Post.new("/sop/webhooks/#{callback_id}")
req["Content-Type"] = "application/json"
req.body = { status: "success" }.to_json
Net::HTTP.start("api.opensop.dev", use_ssl: true) { |h| h.request(req) }
```

