> ## Documentation Index
> Fetch the complete documentation index at: https://docs.aion.to/llms.txt
> Use this file to discover all available pages before exploring further.

# Runtime callbacks

> Authenticate SDK callbacks with Version credentials and preserve caller or deployment-self attribution.

Runtime callbacks are requests from an SDK server to Aion, such as model calls or MCP tool requests.
The runtime authenticates with the **Version access token** obtained from its client ID and client secret.
Do not reuse an incoming user's, guest session's, or invocation bearer for these callbacks.

The Python SDK's model, MCP, A2A, and File clients use the active request's runtime context to select attribution.
This page describes the headers they send and the checks Aion applies. Older clients that send
`Aion-Principal-Selector` must be updated before using this contract.

## Choose the attribution mode

For an inbound request, send one attribution header with the Version bearer.
Aion rejects both headers together, duplicate values, empty values, and malformed caller IDs.
An invalid or expired signed carrier does not select direct or deployment-self mode.

| Request received by the runtime | Callback header |
| - | - |
| Aion supplied a signed usage carrier | Forward `Aion-Usage-Attribution` unchanged. |
| A client contacted the runtime directly | Report the canonical caller in `Aion-Caller-Id`. |
| The deployment initiates work outside an inbound request | Send the Version bearer without either attribution header. |

Aion rejects the retired `Aion-Principal-Selector` header. User requests without callback headers retain user authority.
Version callbacks without attribution or an explicit internal selector use the deployment's current daemon identity.

The former `POST /auth/tokens/exchange` endpoint and AgentIdentity bearer tokens are no longer supported.
Keep the Version bearer for callbacks; Aion resolves and authorizes the acting identity from the attribution mode below.

## Forward Aion usage attribution

```http theme={null}
Authorization: Bearer <version-access-token>
Aion-Usage-Attribution: <signed-usage-carrier-from-the-incoming-request>
```

Aion verifies the carrier's signature, purpose, issuer, audience, time claims, and presenter. It checks whether that
Version may currently act as the carrier's execution principal. Each operation still requires its normal permissions.
The original payer, originator, and outward agent are preserved; they do not select authorization.

The carrier has a 24-hour lifetime for long-running work. It is not the invocation bearer used to authenticate an
incoming request, and it must not be supplied as `Authorization`. Missing or stale executor bindings fail explicitly.

Signed contextual callbacks are supported by model, MCP, A2A, and File mutation ingress.

## Report a direct caller

Direct callbacks require an active deployment with an assigned daemon identity. Aion resolves the current
assignment on each call: that daemon supplies authorization, agent, and execution identity.
The deployment's organization pays. Reassigning or clearing the daemon affects subsequent calls without changing earlier
usage records.

For a direct request with no identifiable caller, report `ExternalAnonymous` with principal ID `external-anonymous`:

```http theme={null}
Authorization: Bearer <version-access-token>
Aion-Caller-Id: aion:v1:ExternalAnonymous:ZXh0ZXJuYWwtYW5vbnltb3Vz
```

Preserve a known anonymous session as `AnonymousSession`, rather than merging it into `ExternalAnonymous`. For a known
Aion user, the following example encodes user ID `00000000-0000-0000-0000-000000000001`:

```http theme={null}
Authorization: Bearer <version-access-token>
Aion-Caller-Id: aion:v1:AionUser:MDAwMDAwMDAtMDAwMC0wMDAwLTAwMDAtMDAwMDAwMDAwMDAx
```

The reported caller is **attribution only**, not proof that the person authenticated. Reporting a user does
not grant their permissions, select their payer, or give the runtime access to that user's tasks and conversations.
Never put a user or session bearer in this header.

Direct caller attribution supports model, MCP, A2A, and File create/replace requests. A2A task access uses the resolved
sending daemon, not the reported caller; the receiving execution hop then updates the executor normally. File mutations
require their ordinary permissions and reject a callback payer that differs from the File's owning organization.
File read/grant behavior and Version-only Fernet key retrieval are unchanged.

In all callback modes, `contexts/get` and `context/get` use the resolved sending identity's caller bindings.
They do not grant access to every conversation owned by the receiving agent, or to the reported caller's conversations.

## Initiate work as the deployment

For work such as integration tests, use the Version bearer without an attribution header:

```http theme={null}
Authorization: Bearer <version-access-token>
```

Aion resolves the deployment's current daemon as originator, agent, executor, and authorization principal.
The deployment's organization pays. The SDK does not fetch or cache the daemon ID.
Each operation still requires its normal permissions, including File owner and payer agreement.

This default applies to model, MCP, A2A, and File create/replace calls.
It does not change other Version endpoints, such as Fernet key retrieval.
If the deployment has no daemon, Aion returns `daemon_identity_required`.
Aion never executes these callbacks as a bare Version principal.

The SDK permits this mode only when no inbound runtime context or explicit attribution exists.
An active runtime context without attribution fails instead of silently selecting deployment-self mode.
An unidentified inbound caller still uses the explicit ExternalAnonymous ID, not this default.
Never remove invalid attribution to retry as the deployment.

## Caller-ID format

Use the same canonical ID as the distribution extension's `callerId` and the invocation JWT subject:

```text theme={null}
aion:v1:<PrincipalType>:<base64url-encoded-UTF-8-principal-ID-without-padding>
```

UUID-based types use the canonical lowercase UUID. External senders retain their provider, tenant, and sender namespace;
do not substitute a raw network user ID. Encoding is reversible, not encryption or authentication. Use
`aion.core.principal.Principal.subject` instead of maintaining a separate encoder.

## Handle callback failures

* `daemon_identity_required`: assign a daemon to the deployment before retrying. Do not select an arbitrary behavior's
  daemon, create a new identity automatically, or fall back to the reported user's credentials.
* Invalid attribution: correct the header or obtain a new valid contextual invocation. Never drop an invalid carrier to
  retry in direct mode.
* Permission denial: grant the deployment daemon the required operation permission. The Project Agent role permits
  model execution and File creation in its organization, but does not grant File update, read, or delete.

The stable configuration code is carried in the operation's error envelope. No metered provider work is dispatched
when resolution fails. Non-streaming model calls return HTTP 400 with `type: "configuration_error"` and
`code: "daemon_identity_required"`. Streaming model calls can return HTTP 200 and carry those same details in an SSE
error event; clients must inspect the stream, not only the HTTP status.
File and MCP configuration failures use HTTP 409.

The Python SDK model helpers raise `AionDaemonIdentityRequired` from `aion.core.exceptions`, including during
synchronous or asynchronous stream consumption. Its `retryable` property is `False`: assign the deployment daemon
before retrying.

## Related pages

* [Caller authentication](/sdk/python/extensibility/caller-authentication)
* [MCP package](/sdk/python/packages/aion-mcp)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.