---
title: "Sign a daemon request with the caller's identity"
method: POST
path: "/interns/{internId}/daemon/sign"
tags: ["Interns"]
---

# Sign a daemon request with the caller's identity

`POST /interns/{internId}/daemon/sign`

Signs the SHA-256 digest of one request the CLI is about to send to the intern daemon, binding it to the intern and to the signed-in member so personal connections resolve. Only an OAuth session from `ori login --oidc` whose grant carries `vault:read` can sign: an API key is refused with 403 because it names no person, and an `interns`-only grant is refused with 403 because a proof releases that user's personal connections. The route is behind the same gate as chat and counts against the chat turn limiter. The response is sent with `Cache-Control: no-store`. The API key selects the caller, workspace and visible interns. An intern's own API key sees only that intern: the collection and every other intern answer 404 to it. There is no default workspace fallback. Requests on regional hostnames such as `eu.openrouter.ai` are refused. [API key](/docs/api-reference/authentication) required.

## Path parameters

- `internId` string, required — ID of an intern visible to the authenticated API key.

## Request body

- SignInternDaemonRequest
  - `bodySha256` string, required — Lower-case hex SHA-256 of the exact bytes the CLI will send as the daemon request body.

## Response `200`

Signature headers for the digest.

- SignInternDaemonResponse — Headers the CLI copies onto the daemon request so the sidecar can verify who is asking.
  - `x-ori-invoke-signature` string, required — Base64 Ed25519 signature over the intern id, timestamp, user and body digest.
  - `x-ori-invoke-timestamp` string, required — Unix seconds at signing; the daemon refuses proofs older than its window.
  - `x-ori-invoke-user` string, required — The verified OAuth subject the proof names. Never taken from the request.

## Other responses

- `400` — The request body is invalid.
- `401` — Missing, unknown or provisioning API key.
- `403` — The caller is an API key, which names no person (`personal_identity_required`), or an OAuth grant without `vault:read` (`insufficient_scope`). Also returned when the key owner no longer has access or the request used a regional hostname.
- `404` — The caller is outside the Intern API programme, the intern is hidden, or lifecycle writes are disabled.
- `408` — The request exceeded its route deadline. The deadline quoted in the message is the route's own, so it differs between operations.
- `413` — The request body is larger than 1048576 bytes.
- `415` — The request body is non-empty and its Content-Type is not application/json.
- `429` — Too many turns for the user or organization this credential acts as (`rate_limited`). Shares the chat turn limiter, reports `retryable: true` and carries `Retry-After`.
- `500` — The request could not be completed. `metadata.reason` says whether to try again: `internal_error` is a transient failure and carries `metadata.retryable: true`, so the same request may be sent again, while `configuration_error` carries `retryable: false` because the next attempt reads the same missing binding or unusable stored credential.

## Changes

- **2026-10-07** `fb6421f3bd76` — 1 info
  - endpoint added

[Change history](https://skmtc.dev/openrouterteam/apis/openrouter-api/changes/interns/:internId/daemon/sign/post.md)

---

[API](https://skmtc.dev/openrouterteam/apis/openrouter-api.md) · [All operations](https://skmtc.dev/openrouterteam/apis/openrouter-api/llms.txt) · [OpenAPI document](https://skmtc.dev/openrouterteam/apis/openrouter-api/revisions/ae97b5c6983d?raw)
