<!-- This file is autogenerated by bin/gen-api-docs.ts. Do not edit by hand. -->

# Interchange Hub API

## Endpoint Index

| Method | Path | Summary |
| ------ | ---- | ------- |
| GET | /api/me | Get current user profile |
| GET | /api/me/principals | List principals across all tenants |
| GET | /api/me/workflows/runs | List running workflow runs across all tenants |
| GET | /api/me/sessions | List sessions across all tenants |
| GET | /api/me/approvals | List pending approvals across all tenants |
| GET | /api/me/git-tokens | List personal git tokens |
| POST | /api/me/git-tokens | Mint a personal access git token |
| DELETE | /api/me/git-tokens/:tokenId | Revoke a personal git token |
| POST | /api/tenants | Create a tenant |
| GET | /api/tenants/:tenantId | Get tenant details |
| PATCH | /api/tenants/:tenantId | Update tenant config |
| GET | /api/tenants/:tenantId/principals | List principals in the tenant |
| GET | /api/tenants/:tenantId/principals/:principalId | Get principal details |
| PATCH | /api/tenants/:tenantId/principals/:principalId | Update principal status |
| DELETE | /api/tenants/:tenantId/principals/:principalId | Remove principal from tenant |
| POST | /api/tenants/:tenantId/members/invite | Invite a user to the tenant |
| GET | /api/tenants/:tenantId/roles | List roles in the tenant |
| POST | /api/tenants/:tenantId/roles | Create a custom role |
| GET | /api/tenants/:tenantId/roles/:roleId | Get role details |
| PATCH | /api/tenants/:tenantId/roles/:roleId | Update a role |
| DELETE | /api/tenants/:tenantId/roles/:roleId | Delete a custom role |
| POST | /api/tenants/:tenantId/principals/:principalId/roles/:roleId | Assign a role to a principal |
| DELETE | /api/tenants/:tenantId/principals/:principalId/roles/:roleId | Remove a role from a principal |
| GET | /api/tenants/:tenantId/grants | List grants in the tenant |
| POST | /api/tenants/:tenantId/grants | Create a grant |
| GET | /api/tenants/:tenantId/grants/:grantId | Get grant details |
| PATCH | /api/tenants/:tenantId/grants/:grantId | Update a grant |
| DELETE | /api/tenants/:tenantId/grants/:grantId | Revoke a grant |
| POST | /api/tenants/:tenantId/principals/:principalId/evaluate | Evaluate grants for a principal |
| POST | /api/tenants/:tenantId/workflows/runs | Deploy an agent instance |
| GET | /api/tenants/:tenantId/workflows/runs | List agent instances |
| GET | /api/tenants/:tenantId/workflows/runs/blobs/:blobId | Fetch a blob by ID |
| GET | /api/tenants/:tenantId/workflows/runs/:runId | Get instance detail |
| DELETE | /api/tenants/:tenantId/workflows/runs/:runId | Stop an instance |
| GET | /api/tenants/:tenantId/workflows/runs/:runId/health | Get instance health |
| GET | /api/tenants/:tenantId/workflows/runs/:runId/offerings | List instance offerings |
| GET | /api/tenants/:tenantId/workflows/runs/:runId/events | SSE event stream |
| POST | /api/tenants/:tenantId/workflows/runs/:runId/mail | Send mail to the agent |
| GET | /api/tenants/:tenantId/workflows/runs/:runId/mail | List mail for an instance |
| GET | /api/tenants/:tenantId/workflows/runs/:runId/turns | List inference turns for an instance |
| GET | /api/tenants/:tenantId/workflows/definitions | List workflow definitions |
| GET | /api/tenants/:tenantId/workflows/definitions/:definitionId/versions | List definition versions |
| POST | /api/tenants/:tenantId/workflows/definitions/:definitionId/rollback | Roll back to a previous version |
| POST | /api/tenants/:tenantId/workflows/instances | Deploy a workflow |
| GET | /api/tenants/:tenantId/workflows/instances | List workflow deployments |
| POST | /api/tenants/:tenantId/workflows/:deploymentId/signals | Deliver a signal to a workflow run |
| POST | /api/tenants/:tenantId/workflows/:deploymentId/mail | Trigger a workflow run |
| GET | /api/tenants/:tenantId/workflows/:deploymentId/runs | List workflow runs |
| GET | /api/tenants/:tenantId/workflows/:deploymentId/runs/:runId/events | Read a workflow run's event log |
| GET | /api/tenants/:tenantId/approvals | List pending approvals in the tenant |
| GET | /api/tenants/:tenantId/approvals/:approvalId | Get approval details |
| POST | /api/tenants/:tenantId/approvals/:approvalId/approve | Approve an action |
| POST | /api/tenants/:tenantId/approvals/:approvalId/reject | Reject an action |
| GET | /api/tenants/:tenantId/wallets | List wallets in the tenant |
| POST | /api/tenants/:tenantId/wallets | Create a wallet |
| GET | /api/tenants/:tenantId/wallets/:walletId | Get wallet details |
| PATCH | /api/tenants/:tenantId/wallets/:walletId | Update wallet config |
| DELETE | /api/tenants/:tenantId/wallets/:walletId | Deactivate a wallet |
| GET | /api/tenants/:tenantId/wallets/:walletId/transactions | List transactions |
| GET | /api/tenants/:tenantId/providers | List providers |
| POST | /api/tenants/:tenantId/providers | Create a provider definition |
| GET | /api/tenants/:tenantId/providers/:providerId | Get provider details |
| PATCH | /api/tenants/:tenantId/providers/:providerId | Update a provider definition |
| DELETE | /api/tenants/:tenantId/providers/:providerId | Remove a provider definition |
| GET | /api/tenants/:tenantId/oauth-clients | List OAuth client registrations |
| POST | /api/tenants/:tenantId/oauth-clients | Register an OAuth client |
| GET | /api/tenants/:tenantId/oauth-clients/:oauthClientId | Get OAuth client details |
| PATCH | /api/tenants/:tenantId/oauth-clients/:oauthClientId | Update an OAuth client registration |
| DELETE | /api/tenants/:tenantId/oauth-clients/:oauthClientId | Remove an OAuth client registration |
| GET | /api/tenants/:tenantId/credentials | List credentials |
| POST | /api/tenants/:tenantId/credentials | Store a credential |
| GET | /api/tenants/:tenantId/credentials/resolve/:name | Resolve a credential by name |
| GET | /api/tenants/:tenantId/credentials/:credentialId | Get credential metadata |
| PATCH | /api/tenants/:tenantId/credentials/:credentialId | Rotate or update a credential |
| DELETE | /api/tenants/:tenantId/credentials/:credentialId | Revoke a credential |
| GET | /api/tenants/:tenantId/offerings | Search offerings |
| POST | /api/tenants/:tenantId/offerings | Register an offering |
| GET | /api/tenants/:tenantId/offerings/:offeringId | Get offering details |
| PATCH | /api/tenants/:tenantId/offerings/:offeringId | Update an offering |
| DELETE | /api/tenants/:tenantId/offerings/:offeringId | Remove an offering |
| GET | /api/tenants/:tenantId/catalog/models | List models owned by the tenant |
| POST | /api/tenants/:tenantId/catalog/models | Create a model |
| GET | /api/tenants/:tenantId/catalog/models/:modelId | Get a model |
| PATCH | /api/tenants/:tenantId/catalog/models/:modelId | Update a model |
| DELETE | /api/tenants/:tenantId/catalog/models/:modelId | Delete a model |
| GET | /api/tenants/:tenantId/catalog/providers | List model providers owned by the tenant |
| POST | /api/tenants/:tenantId/catalog/providers | Create a model provider |
| GET | /api/tenants/:tenantId/catalog/providers/:providerId | Get a model provider |
| PATCH | /api/tenants/:tenantId/catalog/providers/:providerId | Update a model provider |
| DELETE | /api/tenants/:tenantId/catalog/providers/:providerId | Delete a model provider |
| GET | /api/tenants/:tenantId/catalog/offerings | List model offerings owned by the tenant |
| POST | /api/tenants/:tenantId/catalog/offerings | Create a model offering |
| GET | /api/tenants/:tenantId/catalog/offerings/:offeringId | Get a model offering |
| PATCH | /api/tenants/:tenantId/catalog/offerings/:offeringId | Update a model offering |
| DELETE | /api/tenants/:tenantId/catalog/offerings/:offeringId | Delete a model offering |
| GET | /api/tenants/:tenantId/catalog/offerings/:offeringId/pricing | List an offering's pricing history |
| POST | /api/tenants/:tenantId/catalog/offerings/:offeringId/pricing | Add a pricing row to an offering |
| GET | /api/tenants/:tenantId/models | List the models resolved for the tenant |
| GET | /api/tenants/:tenantId/git-tokens | List tenant git tokens |
| POST | /api/tenants/:tenantId/git-tokens | Mint a tenant-bound service git token |
| DELETE | /api/tenants/:tenantId/git-tokens/:tokenId | Revoke a tenant git token |
| GET | /api/tenants/:tenantId/agents/:agentId/logs | Get agent logs |
| GET | /api/tenants/:tenantId/agents/:agentId/metrics | Get agent metrics |
| GET | /api/tenants/:tenantId/traces | Query distributed traces |
| GET | /api/tenants/:tenantId/traces/:traceId | Get a full trace |
| GET | /api/tenants/:tenantId/federation | List federation trust relationships |
| POST | /api/tenants/:tenantId/federation | Establish federation trust |
| DELETE | /api/tenants/:tenantId/federation/:targetTenantId | Revoke federation trust |
| GET | /api/tenants/:tenantId/agents/:agentId/data | List files in agent working directory |
| GET | /api/tenants/:tenantId/agents/:agentId/data/* | Read a file from agent storage |
| GET | /api/tenants/:tenantId/agents/:agentId/history | List commits and checkpoints |
| GET | /api/tenants/:tenantId/agents/:agentId/history/:ref | Show changes in a commit |
| GET | /api/tenants/:tenantId/agents/:agentId/branches | List branches |
| POST | /api/tenants/:tenantId/agents/:agentId/history/:ref/restore | Restore agent data to a previous state |
| GET | /api/tenants/:tenantId/assets | List assets |
| POST | /api/tenants/:tenantId/assets | Create an asset |
| GET | /api/tenants/:tenantId/assets/:assetId | Get asset metadata |
| PUT | /api/tenants/:tenantId/assets/:assetId/tarballs/:filename | Upload a tarball into a package-registry asset |
| DELETE | /api/tenants/:tenantId/assets/:assetId/tarballs/:filename | Delete a tarball from a package-registry asset |
| GET | /api/tenants/:tenantId/assets/:assetId/tarballs | List tarballs in a package-registry asset |

## User

### GET /api/me
Get current user profile

200: UserProfile -- User profile
401: ErrorResponse -- Not authenticated

### GET /api/me/principals
List principals across all tenants

Returns all of the authenticated user's principals across tenants, with tenant name, roles, and status in each.

Query: cursor?, limit?

200: unknown -- List of principals across tenants
401: ErrorResponse -- Not authenticated

### GET /api/me/workflows/runs
List running workflow runs across all tenants

Aggregates running workflow runs from all tenants the user belongs to. Each result is tagged with tenantId.

Query: cursor?, limit?

200: unknown -- Runs across tenants

### GET /api/me/sessions
List sessions across all tenants

Aggregates active sessions from all tenants the user belongs to. Each result is tagged with tenantId.

200: SessionSummary[] -- Sessions across tenants

### GET /api/me/approvals
List pending approvals across all tenants

Aggregates pending approval requests from all tenants the user belongs to. Each result is tagged with tenantId.

200: ApprovalSummary[] -- Approvals across tenants

## Git Tokens

### GET /api/me/git-tokens
List personal git tokens

Lists the authenticated user's personal access tokens (`kind: "pat"`). Secrets are never returned; the plaintext is shown only at mint time.

Query: cursor?, limit?

200: unknown -- List of git tokens
401: ErrorResponse -- Not authenticated

### POST /api/me/git-tokens
Mint a personal access git token

Mints a personal access token (`kind: "pat"`) for the authenticated user. The plaintext secret is returned exactly once in the response. An optional `tenantId` restricts the token to a single tenant.

Body: unknown

201: unknown -- Token minted
400: ErrorResponse -- Validation error
401: ErrorResponse -- Not authenticated

### DELETE /api/me/git-tokens/:tokenId
Revoke a personal git token

Soft-revokes a personal access token by setting `revokedAt`. Only the owning user may revoke their own tokens.

204: (no content) -- Token revoked
401: ErrorResponse -- Not authenticated
404: ErrorResponse -- Token not found or not owned by the authenticated user

### GET /api/tenants/:tenantId/git-tokens
List tenant git tokens

Lists service tokens (`kind: "svc"`) bound to this tenant. Secrets are never returned; the plaintext is shown only at mint time.

Query: cursor?, limit?

200: unknown -- List of git tokens

### POST /api/tenants/:tenantId/git-tokens
Mint a tenant-bound service git token

Mints a service token (`kind: "svc"`) bound to the requesting tenant. The plaintext secret is returned exactly once in the response and is never persisted in plaintext.

Body: unknown

201: unknown -- Token minted
400: ErrorResponse -- Validation error

### DELETE /api/tenants/:tenantId/git-tokens/:tokenId
Revoke a tenant git token

Soft-revokes a tenant-bound git token by setting `revokedAt`. The row is retained for audit.

204: (no content) -- Token revoked
404: ErrorResponse -- Token not found

## Tenants

### POST /api/tenants
Create a tenant

Creates a new tenant. The authenticated user becomes the owner with a principal and default owner role.

Body: CreateTenant

201: TenantResponse -- Tenant created
400: ErrorResponse -- Validation error

### GET /api/tenants/:tenantId
Get tenant details

200: TenantResponse -- Tenant details
403: ErrorResponse -- Not a member of this tenant
404: ErrorResponse -- Tenant not found

### PATCH /api/tenants/:tenantId
Update tenant config

Requires admin or higher grant within the tenant.

Body: UpdateTenant

200: TenantResponse -- Tenant updated
403: ErrorResponse -- Insufficient grants

### GET /api/tenants/:tenantId/federation
List federation trust relationships

Query: cursor?, limit?

200: unknown -- Federation trusts

### POST /api/tenants/:tenantId/federation
Establish federation trust

Creates a trust relationship with another tenant for cross-tenant agent discovery and interaction.

Body: CreateFederationTrust

201: FederationTrust -- Trust established
400: ErrorResponse -- Validation error

### DELETE /api/tenants/:tenantId/federation/:targetTenantId
Revoke federation trust

204: (no content) -- Trust revoked
404: ErrorResponse -- Trust not found

## Principals

### GET /api/tenants/:tenantId/principals
List principals in the tenant

Lists all principals (users, agents, and workflow deployments) in the tenant. Filterable by kind and status.

Query: kind?: user|agent|workflow, status?: active|suspended|invited|deactivated, cursor?, limit?

200: unknown -- List of principals

### GET /api/tenants/:tenantId/principals/:principalId
Get principal details

Returns principal details including kind, status, assigned roles, and effective grants.

200: PrincipalResponse -- Principal details
404: ErrorResponse -- Principal not found

### PATCH /api/tenants/:tenantId/principals/:principalId
Update principal status

Activate, suspend, or deactivate a principal.

Body: UpdatePrincipal

200: PrincipalResponse -- Principal updated
403: ErrorResponse -- Insufficient grants

### DELETE /api/tenants/:tenantId/principals/:principalId
Remove principal from tenant

Removes a user or agent principal from the tenant. For agents, use agent deletion instead.

204: (no content) -- Principal removed
403: ErrorResponse -- Insufficient grants

### POST /api/tenants/:tenantId/members/invite
Invite a user to the tenant

Invites a user by email. Creates a principal with invited status and optionally assigns a role.

Body: InviteMember

201: PrincipalResponse -- Invitation sent
400: ErrorResponse -- Validation error

## Roles

### GET /api/tenants/:tenantId/roles
List roles in the tenant

Lists both system roles (owner, admin, member) and custom roles.

Query: cursor?, limit?

200: unknown -- List of roles

### POST /api/tenants/:tenantId/roles
Create a custom role

Body: CreateRole

201: RoleResponse -- Role created
400: ErrorResponse -- Validation error

### GET /api/tenants/:tenantId/roles/:roleId
Get role details

Returns role details including attached grants.

200: RoleResponse -- Role details
404: ErrorResponse -- Role not found

### PATCH /api/tenants/:tenantId/roles/:roleId
Update a role

Update name or description. System roles cannot be modified.

Body: UpdateRole

200: RoleResponse -- Role updated
403: ErrorResponse -- Cannot modify system role

### DELETE /api/tenants/:tenantId/roles/:roleId
Delete a custom role

Deletes a custom role. Fails if principals are currently assigned to it. System roles cannot be deleted.

204: (no content) -- Role deleted
400: ErrorResponse -- Role still assigned to principals
403: ErrorResponse -- Cannot delete system role

### POST /api/tenants/:tenantId/principals/:principalId/roles/:roleId
Assign a role to a principal

Assigns a role to a user or agent principal within the tenant.

204: (no content) -- Role assigned
404: ErrorResponse -- Principal or role not found

### DELETE /api/tenants/:tenantId/principals/:principalId/roles/:roleId
Remove a role from a principal

204: (no content) -- Role removed
404: ErrorResponse -- Assignment not found

## Grants

### GET /api/tenants/:tenantId/grants
List grants in the tenant

Lists all grants. Filterable by principalId, roleId, resource pattern, and effect.

Query: principalId?, roleId?, resource?, effect?: allow|deny|ask, cursor?, limit?

200: unknown -- List of grants

### POST /api/tenants/:tenantId/grants
Create a grant

Creates a grant targeting either a role or a principal directly. Exactly one of roleId or principalId must be provided.

Body: CreateGrant

201: GrantResponse -- Grant created
400: ErrorResponse -- Validation error

### GET /api/tenants/:tenantId/grants/:grantId
Get grant details

200: GrantResponse -- Grant details
404: ErrorResponse -- Grant not found

### PATCH /api/tenants/:tenantId/grants/:grantId
Update a grant

Update effect, conditions, or expiry on an existing grant.

Body: UpdateGrant

200: GrantResponse -- Grant updated
404: ErrorResponse -- Grant not found

### DELETE /api/tenants/:tenantId/grants/:grantId
Revoke a grant

204: (no content) -- Grant revoked
404: ErrorResponse -- Grant not found

### POST /api/tenants/:tenantId/principals/:principalId/evaluate
Evaluate grants for a principal

Evaluates what would happen if a principal attempted an operation. Returns the resolved effect and all matching grants. Useful for debugging authorization.

Body: EvaluateRequest

200: EvaluateResult -- Evaluation result
404: ErrorResponse -- Principal not found

## Instances

### POST /api/tenants/:tenantId/workflows/runs
Deploy an agent instance

Creates a new running instance of the specified agent definition. Resolves the definition's model requirements against the tenant catalog into an ordered inference-source list, materializes grants on a new agent principal, provisions the agent on a sidecar, and starts it. The invoker can provide invokerGrants to delegate additional capabilities, and modelPreferences to reorder or restrict the resolved providers for the session.

Body: CreateWorkflowRun

201: WorkflowRunResponse -- Instance deployed
404: ErrorResponse -- Agent definition not found
409: ErrorResponse -- Agent not launchable
502: ErrorResponse -- Sidecar unavailable

### GET /api/tenants/:tenantId/workflows/runs
List agent instances

Lists agent instances in the tenant. Filterable by definitionId and status.

Query: definitionId?, status?: deployed|running|updating|error|stopped, cursor?, limit?

200: unknown -- List of instances

### GET /api/tenants/:tenantId/workflows/runs/blobs/:blobId
Fetch a blob by ID

Returns raw bytes for a MIME part. Blob IDs are issued by the mail parsing layer.

200: (no content) -- Blob bytes
400: ErrorResponse -- Invalid blob ID
403: ErrorResponse -- Forbidden
404: ErrorResponse -- Blob not found

### GET /api/tenants/:tenantId/workflows/runs/:runId
Get instance detail

Returns instance runtime state including status, public key, and sidecar assignment.

200: WorkflowRunResponse -- Instance detail
404: ErrorResponse -- Instance not found

### DELETE /api/tenants/:tenantId/workflows/runs/:runId
Stop an instance

Stops the running instance and undeploys the agent from the sidecar.

204: (no content) -- Instance stopped
404: ErrorResponse -- Instance not found
409: ErrorResponse -- Instance already stopped
502: ErrorResponse -- Sidecar unavailable

### GET /api/tenants/:tenantId/workflows/runs/:runId/health
Get instance health

Returns liveness and readiness for a running instance. Liveness reflects whether the instance's sidecar connection is active. Readiness reflects whether the instance has an active event collector and can process work.

200: WorkflowRunHealth -- Health status
404: ErrorResponse -- Instance not found
410: ErrorResponse -- Instance stopped

### GET /api/tenants/:tenantId/workflows/runs/:runId/offerings
List instance offerings

Returns the offerings associated with the instance's agent definition. These represent the capabilities the instance can provide.

200: OfferingDetail[] -- List of offerings
404: ErrorResponse -- Instance not found

### GET /api/tenants/:tenantId/workflows/runs/:runId/events
SSE event stream

Server-Sent Events stream for agent events. Use POST .../messages for client-to-server messaging.

200: SSE stream -- SSE event stream
404: ErrorResponse -- Instance not found
410: ErrorResponse -- Instance stopped

### POST /api/tenants/:tenantId/workflows/runs/:runId/mail
Send mail to the agent

Persists the user message as a mail record and dispatches it to the running agent. Returns JMAP Email-shaped response.

Body: SendMessage

201: MailResponse -- Mail sent
400: AttachmentErrorResponse -- Attachment validation error. Each variant carries a structured code (oversize_attachment, disallowed_mime_type, malformed_base64, oversize_total) with the offending index and limits. A malformed request body that fails SendMessage validation returns the generic error shape instead.
404: ErrorResponse -- Instance not found
409: ErrorResponse -- Instance not running
413: ErrorResponse -- Request body exceeds the maximum allowed size
502: ErrorResponse -- Sidecar unavailable

### GET /api/tenants/:tenantId/workflows/runs/:runId/mail
List mail for an instance

Returns parsed JMAP Email objects in reverse chronological order. Cursor-paginated.

Query: cursor?, limit?

200: unknown -- List of mail
404: ErrorResponse -- Instance not found

### GET /api/tenants/:tenantId/workflows/runs/:runId/turns
List inference turns for an instance

Returns inference turns with their parts in reverse chronological order. Cursor-paginated.

Query: cursor?, limit?

200: unknown -- List of inference turns
404: ErrorResponse -- Instance not found

## Workflow Definitions

### GET /api/tenants/:tenantId/workflows/definitions
List workflow definitions

Lists the workflow definitions for the tenant, most recent first.

Query: cursor?, limit?

200: unknown -- List of workflow definitions

### GET /api/tenants/:tenantId/workflows/definitions/:definitionId/versions
List definition versions

Lists all versions of a workflow definition with status.

Query: cursor?, limit?

200: unknown -- List of versions
404: ErrorResponse -- Definition not found

### POST /api/tenants/:tenantId/workflows/definitions/:definitionId/rollback
Roll back to a previous version

Activates the specified version and stops the current one; repoints currentVersion.

Body: WorkflowRollbackRequest

200: WorkflowDefinitionResponse -- Rollback applied
400: ErrorResponse -- Invalid version
404: ErrorResponse -- Definition not found

## Workflows

### POST /api/tenants/:tenantId/workflows/instances
Deploy a workflow

Hydrates a workflow definition from its workflow asset's workflow.json and deploys it through the general multi-step workflow deploy path. Returns the deployment record.

Body: unknown

201: unknown -- Workflow deployed
404: ErrorResponse -- Workflow asset not found
409: ErrorResponse -- Workflow definition could not be hydrated
500: ErrorResponse -- Deployment projection row missing after deploy
502: ErrorResponse -- Sidecar unavailable

### GET /api/tenants/:tenantId/workflows/instances
List workflow deployments

Lists the workflow deployments for the tenant, most recent first.

200: unknown -- List of workflow deployments

### POST /api/tenants/:tenantId/workflows/:deploymentId/signals
Deliver a signal to a workflow run

Delivers a caller-supplied, stable signal to the named run of a workflow deployment. The signalId must be supplied by the caller; the run state machine dedups on it.

Body: unknown

202: (no content) -- Signal accepted for delivery
400: ErrorResponse -- Reserved signal name or a runId that is not the deployment's addressable run
404: ErrorResponse -- Workflow deployment not found
409: ErrorResponse -- Workflow run has not started, is terminal, its deployment allocation is no longer active, or the signalId conflicts with a previously accepted payload
502: ErrorResponse -- Sidecar unavailable
503: ErrorResponse -- Durable workflow dispatch unavailable

### POST /api/tenants/:tenantId/workflows/:deploymentId/mail
Trigger a workflow run

Delivers a fresh signed conversation message to the deployment's stable top-level run. The first accepted message fires that run; while it remains live, later messages may resume its onTrigger input. A terminal deployment run cannot be fired again. The returned messageId identifies this trigger occurrence.

Body: SendMessage

202: unknown -- Trigger accepted for delivery
400: ErrorResponse -- Attachment validation error. Each variant carries a structured code (oversize_attachment, disallowed_mime_type, malformed_base64, oversize_total) with the offending index and limits. A malformed request body that fails SendMessage validation returns the generic error shape instead.
404: ErrorResponse -- Workflow deployment not found
409: ErrorResponse -- Deployment address is not routable, its allocation is no longer active, or its top-level run is terminal
413: ErrorResponse -- Request body exceeds the maximum allowed size
503: ErrorResponse -- Durable workflow dispatch unavailable

### GET /api/tenants/:tenantId/workflows/:deploymentId/runs
List workflow runs

Lists the run ids present in the deployment's workflow-run event log. Returns an empty list when no run has committed events yet.

200: unknown -- List of run ids
404: ErrorResponse -- Workflow deployment not found

### GET /api/tenants/:tenantId/workflows/:deploymentId/runs/:runId/events
Read a workflow run's event log

Returns the seq-ordered event projection (RunStarted, StepStarted, StepCompleted, SignalAwaited, RunCompleted, etc.) for a single run. The full event log is returned in ascending seq order; an unknown run returns an empty list.

200: unknown -- Seq-ordered run events
404: ErrorResponse -- Workflow deployment not found

## Approvals

### GET /api/tenants/:tenantId/approvals
List pending approvals in the tenant

Returns pending approval requests within this tenant, newest first.

Query: cursor?, limit?

200: unknown -- List of pending approvals
403: ErrorResponse -- Caller lacks the tenant-wide approval grant

### GET /api/tenants/:tenantId/approvals/:approvalId
Get approval details

Returns the approver-facing tool snapshot, status, and originating deployment for one approval.

200: ApprovalResponse -- Approval details
403: ErrorResponse -- Caller lacks the approval grant
404: ErrorResponse -- Approval not found

### POST /api/tenants/:tenantId/approvals/:approvalId/approve
Approve an action

Approves the pending action. With scope 'once', the approval is one-time. Scope 'always' is not yet supported: a standing grant requires the tool identity, which the suspend path does not yet capture.

Body: ApproveAction

200: ApprovalResponse -- Action approved
400: ErrorResponse -- Unsupported scope
403: ErrorResponse -- Approver lacks the approval resolve grant
404: ErrorResponse -- Approval not found
409: ErrorResponse -- Approval already resolved (takes precedence on retries), workflow run no longer running, or workflow deployment unavailable
503: ErrorResponse -- Durable workflow dispatch unavailable

### POST /api/tenants/:tenantId/approvals/:approvalId/reject
Reject an action

Rejects the pending action. An optional message provides feedback to the agent.

Body: RejectAction

200: ApprovalResponse -- Action rejected
403: ErrorResponse -- Approver lacks the approval resolve grant
404: ErrorResponse -- Approval not found
409: ErrorResponse -- Approval already resolved (takes precedence on retries), workflow run no longer running, or workflow deployment unavailable
503: ErrorResponse -- Durable workflow dispatch unavailable

## Wallets

### GET /api/tenants/:tenantId/wallets
List wallets in the tenant

Query: cursor?, limit?

200: unknown -- List of wallets

### POST /api/tenants/:tenantId/wallets
Create a wallet

Creates a wallet with the specified payment backend and currency. Access for agents is managed through grants.

Body: CreateWallet

201: WalletResponse -- Wallet created
400: ErrorResponse -- Validation error

### GET /api/tenants/:tenantId/wallets/:walletId
Get wallet details

Returns wallet details including current balance.

200: WalletResponse -- Wallet details
404: ErrorResponse -- Wallet not found

### PATCH /api/tenants/:tenantId/wallets/:walletId
Update wallet config

Body: UpdateWallet

200: WalletResponse -- Wallet updated
404: ErrorResponse -- Wallet not found

### DELETE /api/tenants/:tenantId/wallets/:walletId
Deactivate a wallet

204: (no content) -- Wallet deactivated
404: ErrorResponse -- Wallet not found

### GET /api/tenants/:tenantId/wallets/:walletId/transactions
List transactions

Transaction history for a wallet. Filterable by run, date range, and status.

Query: runId?, startTime?, endTime?, status?: pending|completed|failed, cursor?, limit?

200: unknown -- List of transactions

## Providers

### GET /api/tenants/:tenantId/providers
List providers

Lists provider definitions for the tenant, including those inherited from ancestor tenants.

Query: inherited?: true|false, cursor?, limit?

200: unknown -- List of providers

### POST /api/tenants/:tenantId/providers
Create a provider definition

Defines a new service provider for the tenant. The plugin field determines how Interchange integrates with the service.

Body: CreateProvider

201: ProviderResponse -- Provider created
400: ErrorResponse -- Validation error
409: ErrorResponse -- Provider name already exists in this tenant

### GET /api/tenants/:tenantId/providers/:providerId
Get provider details

200: ProviderResponse -- Provider details
404: ErrorResponse -- Provider not found

### PATCH /api/tenants/:tenantId/providers/:providerId
Update a provider definition

Only providers owned by this tenant can be updated.

Body: UpdateProvider

200: ProviderResponse -- Provider updated
404: ErrorResponse -- Provider not found

### DELETE /api/tenants/:tenantId/providers/:providerId
Remove a provider definition

Only providers owned by this tenant can be removed.

204: (no content) -- Provider removed
404: ErrorResponse -- Provider not found

## OAuth Clients

### GET /api/tenants/:tenantId/oauth-clients
List OAuth client registrations

Lists OAuth client registrations for the tenant. Secrets are never returned.

Query: cursor?, limit?

200: unknown -- List of OAuth clients

### POST /api/tenants/:tenantId/oauth-clients
Register an OAuth client

Registers an OAuth client (client_id/client_secret) for a provider. The provider must exist in the tenant or its ancestors.

Body: CreateOAuthClient

201: OAuthClientResponse -- OAuth client registered
400: ErrorResponse -- Validation error
404: ErrorResponse -- Provider not found
409: ErrorResponse -- OAuth client already exists for this provider in this tenant

### GET /api/tenants/:tenantId/oauth-clients/:oauthClientId
Get OAuth client details

Returns OAuth client metadata. Secrets are never included.

200: OAuthClientResponse -- OAuth client details
404: ErrorResponse -- OAuth client not found

### PATCH /api/tenants/:tenantId/oauth-clients/:oauthClientId
Update an OAuth client registration

Body: UpdateOAuthClient

200: OAuthClientResponse -- OAuth client updated
404: ErrorResponse -- OAuth client not found

### DELETE /api/tenants/:tenantId/oauth-clients/:oauthClientId
Remove an OAuth client registration

204: (no content) -- OAuth client removed
404: ErrorResponse -- OAuth client not found

## Credentials

### GET /api/tenants/:tenantId/credentials
List credentials

Lists credential metadata. Secrets are never returned. Filterable by owner type.

Query: owner?: me|org|all, cursor?, limit?

200: unknown -- List of credentials

### POST /api/tenants/:tenantId/credentials
Store a credential

Stores a credential (API key, OAuth token, etc.). The secret is stored securely and never returned in subsequent reads. A provider must be specified.

Body: CreateCredential

201: CredentialResponse -- Credential stored
400: ErrorResponse -- Validation error
404: ErrorResponse -- Provider not found
409: ErrorResponse -- Credential name already exists in this tenant

### GET /api/tenants/:tenantId/credentials/resolve/:name
Resolve a credential by name

Resolves a credential by name, walking the tenant hierarchy. Returns metadata only (no secret). Useful for discovering which credential an agent would get.

200: CredentialResponse -- Credential metadata
404: ErrorResponse -- Credential not found

### GET /api/tenants/:tenantId/credentials/:credentialId
Get credential metadata

Returns credential metadata. The secret is never included. Supports hierarchy-aware access.

200: CredentialResponse -- Credential metadata
404: ErrorResponse -- Credential not found

### PATCH /api/tenants/:tenantId/credentials/:credentialId
Rotate or update a credential

Only credentials owned by this tenant can be updated.

Body: UpdateCredential

200: CredentialResponse -- Credential updated
404: ErrorResponse -- Credential not found

### DELETE /api/tenants/:tenantId/credentials/:credentialId
Revoke a credential

Only credentials owned by this tenant can be revoked.

204: (no content) -- Credential revoked
404: ErrorResponse -- Credential not found

## Discovery

### GET /api/tenants/:tenantId/offerings
Search offerings

Searches offerings across discoverable agents in the tenant and federated tenants. Filterable by offering name, pricing range, and payment method.

Query: name?, minPrice?, maxPrice?, paymentMethod?, cursor?, limit?

200: unknown -- List of offerings

### POST /api/tenants/:tenantId/offerings
Register an offering

Registers an offering for a workflow definition. The definition must belong to the tenant.

Body: CreateOffering

201: OfferingDetail -- Offering registered
400: ErrorResponse -- Validation error
404: ErrorResponse -- Workflow definition not found

### GET /api/tenants/:tenantId/offerings/:offeringId
Get offering details

Returns pricing, definition info, and request/response type information.

200: OfferingDetail -- Offering details
404: ErrorResponse -- Offering not found

### PATCH /api/tenants/:tenantId/offerings/:offeringId
Update an offering

Body: UpdateOffering

200: OfferingDetail -- Offering updated
404: ErrorResponse -- Offering not found

### DELETE /api/tenants/:tenantId/offerings/:offeringId
Remove an offering

204: (no content) -- Offering removed
404: ErrorResponse -- Offering not found

### GET /api/tenants/:tenantId/models
List the models resolved for the tenant

Returns the tenant's resolved catalog: every model visible after applying inheritance, shadowing, and disable suppression, broken down by the providers that offer it with each offering's active price per currency.

200: ModelInfo[] -- Resolved models

## Catalog

### GET /api/tenants/:tenantId/catalog/models
List models owned by the tenant

Lists the models created directly on this tenant. Models inherited from ancestor tenants are not included; use the model discovery endpoint to see the resolved catalog.

Query: cursor?, limit?

200: unknown -- List of models

### POST /api/tenants/:tenantId/catalog/models
Create a model

Creates a tenant-local model. Reusing the canonical name of an inherited model shadows that model for this tenant and its descendants.

Body: CreateModel

201: ModelResponse -- Model created
409: ErrorResponse -- A model with this canonical name already exists

### GET /api/tenants/:tenantId/catalog/models/:modelId
Get a model

200: ModelResponse -- Model details
404: ErrorResponse -- Model not found

### PATCH /api/tenants/:tenantId/catalog/models/:modelId
Update a model

Body: UpdateModel

200: ModelResponse -- Model updated
404: ErrorResponse -- Model not found

### DELETE /api/tenants/:tenantId/catalog/models/:modelId
Delete a model

Removes the model and cascades to the offerings that reference it. Running instances resolved through those offerings fail over to the next eligible source.

204: (no content) -- Model removed
404: ErrorResponse -- Model not found

### GET /api/tenants/:tenantId/catalog/providers
List model providers owned by the tenant

Lists the model providers created directly on this tenant. Providers inherited from ancestor tenants are not included.

Query: cursor?, limit?

200: unknown -- List of model providers

### POST /api/tenants/:tenantId/catalog/providers
Create a model provider

Registers an inference endpoint authenticated by exactly one of a credential or a wallet. Supplying both or neither is rejected.

Body: CreateModelProvider

201: ModelProviderResponse -- Provider created
400: ErrorResponse -- Exactly one of credentialId or walletId is required
404: ErrorResponse -- Credential not found in this tenant
409: ErrorResponse -- Provider name already exists in this tenant

### GET /api/tenants/:tenantId/catalog/providers/:providerId
Get a model provider

200: ModelProviderResponse -- Provider details
404: ErrorResponse -- Provider not found

### PATCH /api/tenants/:tenantId/catalog/providers/:providerId
Update a model provider

Updates a provider's name, base URL, or disabled flag. Changing the authentication binding is not supported; delete and recreate the provider to repoint it.

Body: UpdateModelProvider

200: ModelProviderResponse -- Provider updated
404: ErrorResponse -- Provider not found
409: ErrorResponse -- Provider name already exists in this tenant

### DELETE /api/tenants/:tenantId/catalog/providers/:providerId
Delete a model provider

Removes the provider and cascades to the offerings that reference it. Running instances resolved through those offerings fail over to the next eligible source.

204: (no content) -- Provider removed
404: ErrorResponse -- Provider not found

### GET /api/tenants/:tenantId/catalog/offerings
List model offerings owned by the tenant

Lists the model offerings created directly on this tenant. Offerings inherited from ancestor tenants are not included; use the model discovery endpoint to see the resolved catalog.

Query: cursor?, limit?

200: unknown -- List of model offerings

### POST /api/tenants/:tenantId/catalog/offerings
Create a model offering

Pairs a tenant-owned model with a tenant-owned provider. To offer an inherited model or provider, first create a tenant-local copy of it (shadowing).

Body: CreateModelOffering

201: ModelOfferingResponse -- Offering created
404: ErrorResponse -- Model or provider not found in this tenant
409: ErrorResponse -- Offering already exists for this model and provider

### GET /api/tenants/:tenantId/catalog/offerings/:offeringId
Get a model offering

200: ModelOfferingResponse -- Offering details
404: ErrorResponse -- Offering not found

### PATCH /api/tenants/:tenantId/catalog/offerings/:offeringId
Update a model offering

Body: UpdateModelOffering

200: ModelOfferingResponse -- Offering updated
404: ErrorResponse -- Offering not found

### DELETE /api/tenants/:tenantId/catalog/offerings/:offeringId
Delete a model offering

Removes the offering and its pricing history. Running instances resolved through it fail over to the next eligible source.

204: (no content) -- Offering removed
404: ErrorResponse -- Offering not found

### GET /api/tenants/:tenantId/catalog/offerings/:offeringId/pricing
List an offering's pricing history

Returns the full append-only pricing history for an offering, every currency and effective-from date, newest first.

200: PricingRowResponse[] -- Pricing rows
404: ErrorResponse -- Offering not found

### POST /api/tenants/:tenantId/catalog/offerings/:offeringId/pricing
Add a pricing row to an offering

Appends a pricing row. Pricing is append-only: a price change inserts a new row with a later effective-from rather than editing an existing one, so historical cost attribution stays accurate.

Body: CreatePricingRow

201: PricingRowResponse -- Pricing row created
400: ErrorResponse -- effectiveFrom is not a valid timestamp
404: ErrorResponse -- Offering not found
409: ErrorResponse -- A pricing row already exists for this currency and effective-from

## Observability

### GET /api/tenants/:tenantId/agents/:agentId/logs
Get agent logs

Structured logs for an agent. Filterable by level and time range.

Query: level?: debug|info|warn|error, startTime?, endTime?

200: LogEntry[] -- Log entries
404: ErrorResponse -- Agent not found

### GET /api/tenants/:tenantId/agents/:agentId/metrics
Get agent metrics

Returns throughput, latency, error rates, token usage, and cost metrics.

200: MetricsResponse -- Agent metrics
404: ErrorResponse -- Agent not found

### GET /api/tenants/:tenantId/traces
Query distributed traces

Searches traces within the tenant. Filterable by agent, session, time range, and trace ID.

Query: agentId?, sessionId?, traceId?, startTime?, endTime?

200: SpanResponse[] -- List of traces

### GET /api/tenants/:tenantId/traces/:traceId
Get a full trace

Returns all spans in a trace across agent boundaries.

200: TraceResponse -- Trace with spans
404: ErrorResponse -- Trace not found

## Agent Data

### GET /api/tenants/:tenantId/agents/:agentId/data
List files in agent working directory

200: FileEntry[] -- File listing
404: ErrorResponse -- Agent not found

### GET /api/tenants/:tenantId/agents/:agentId/data/*
Read a file from agent storage

Reads a file by path from the agent's local storage.

200: FileContent -- File content
404: ErrorResponse -- File or agent not found

### GET /api/tenants/:tenantId/agents/:agentId/history
List commits and checkpoints

Returns the agent's change history with commit messages and timestamps.

200: HistoryEntry[] -- History entries

### GET /api/tenants/:tenantId/agents/:agentId/history/:ref
Show changes in a commit

Returns the files changed in a specific commit with additions/deletions counts.

200: CommitDetail -- Commit details
404: ErrorResponse -- Commit not found

### GET /api/tenants/:tenantId/agents/:agentId/branches
List branches

Lists branches in the agent's data repository.

200: BranchInfo[] -- List of branches

### POST /api/tenants/:tenantId/agents/:agentId/history/:ref/restore
Restore agent data to a previous state

Restores the agent's working directory to the state at the specified commit.

204: (no content) -- Data restored
404: ErrorResponse -- Commit not found

## Assets

### GET /api/tenants/:tenantId/assets
List assets

Lists assets for the tenant. With inherited=true (the default), assets defined on ancestor tenants are included; descendant tenants shadow ancestors when they declare the same (kind, name) pair. Each row carries an `origin` tag identifying the tenant that supplied it.

Query: kind?, inherited?: true|false

200: AssetWithOriginResponse[] -- List of assets

### POST /api/tenants/:tenantId/assets
Create an asset

Inserts an asset row and initializes the backing git repository with a hub-signed genesis commit and the asset-route .gitignore body.

Body: unknown

201: unknown -- Asset created
400: ErrorResponse -- Validation error
409: ErrorResponse -- Asset already exists

### GET /api/tenants/:tenantId/assets/:assetId
Get asset metadata

Returns asset metadata. Resolves through the tenant hierarchy: assets declared on the tenant or any ancestor are visible. Sibling-tenant assets return 404 so callers cannot probe for cross-tenant existence.

200: AssetResponse -- Asset metadata
404: ErrorResponse -- Asset not found

### PUT /api/tenants/:tenantId/assets/:assetId/tarballs/:filename
Upload a tarball into a package-registry asset

Commits raw tarball bytes at tarballs/<filename> in the package-registry asset's git tree. Overwrites permitted. The kind handler validates the tarball's package.json before the commit is accepted.

200: unknown -- Tarball stored
400: ErrorResponse -- Invalid filename or rejected content
404: ErrorResponse -- Asset not found

### DELETE /api/tenants/:tenantId/assets/:assetId/tarballs/:filename
Delete a tarball from a package-registry asset

Removes the named tarball from the package-registry asset and commits the resulting tree. Returns 404 if the asset or filename does not exist.

200: unknown -- Tarball removed
400: ErrorResponse -- Invalid filename
404: ErrorResponse -- Asset or filename not found

### GET /api/tenants/:tenantId/assets/:assetId/tarballs
List tarballs in a package-registry asset

Returns the current set of tarballs under tarballs/ for the package-registry asset, with size and SRI integrity for each entry.

200: unknown -- Tarball list
404: ErrorResponse -- Asset not found

## Type Reference

### ApprovalResponse
`{ agentAddress: string, correlationId: string, createdAt: string, deploymentId: string, id: string, resolvedAt: string | null, runId: string, scope: "always" | "once" | null, status: "approved" | "expired" | "pending" | "rejected" | "timeout", tenantId: string, timeoutAt: string | null, toolArguments: { [string]: unknown }, toolDefinition: { [string]: unknown }, updatedAt: string }`
Source: packages/types/src/approvals.ts

**correlationId**: Ties the approval to the suspension it resolves. The parked run awaits the control signal keyed by this id.
**deploymentId**: The workflow deployment the approval originates from. Every approval is raised during a workflow run; there is no launched single agent or agent-definition row behind it.
**timeoutAt**: Deadline after which the approval expires. Null records a hold-indefinitely approval with no deadline.
**toolDefinition**: The approver-facing tool snapshot (name, description, input schema) captured at suspend time.

### ApprovalSummary
`{ action: string, createdAt: string, definitionId: string, definitionName: string, id: string, resource: string, sessionId: string, tenantId: string, tenantName: string }`
Source: packages/types/src/me.ts

**sessionId**: Internal FK to the session channel. The run ID can be resolved via the session relationship.

### ApproveAction
`{ scope: "always" | "once" }`
Source: packages/types/src/approvals.ts

### AssetResponse
`{ createdAt: string, creatorPrincipalId: string | null, displayName: string | null, id: string, kind: string, name: string, tenantId: string, updatedAt: string }`
Source: packages/types/src/assets.ts

**kind**: Category of the asset, used together with `name` to address it. The (kind, name) pair is what callers resolve against, and it is unique within a tenant.

### AssetWithOriginResponse
`{ createdAt: string, creatorPrincipalId: string | null, displayName: string | null, id: string, kind: string, name: string, origin: { direct: boolean, tenantId: string }, tenantId: string, updatedAt: string }`
Source: packages/types/src/assets.ts

**kind**: Category of the asset, used together with `name` to address it. The (kind, name) pair is what callers resolve against, and it is unique within a tenant.
**origin**: Which tenant in the hierarchy this asset row came from, distinguishing locally-defined assets from inherited ones.

### AttachmentErrorResponse
`{ error: { attachmentIndex: number, byteLength: number, code: "oversize_attachment", limitBytes: number, message: string } | { attachmentIndex: number, code: "disallowed_mime_type", message: string, mimeType: string } | { attachmentIndex: number, code: "invalid_attachment_name", message: string } | { attachmentIndex: number, code: "malformed_base64", message: string } | { code: "oversize_total", limitBytes: number, message: string, totalBytes: number } }`
Source: packages/types/src/sessions.ts

### BranchInfo
`{ name: string, isCurrent?: boolean, lastCommitAt?: string | null, lastCommitMessage?: string | null, lastCommitRef?: string | null }`
Source: packages/types/src/agent-data.ts

### CommitDetail
`{ author: string, changes: { path: string, status: "added" | "deleted" | "modified", additions?: number, deletions?: number }[], message: string, ref: string, timestamp: string }`
Source: packages/types/src/agent-data.ts

### CreateCredential
`{ name: string, providerId: string, secret: string, type: "api_key" | "certificate" | "oauth_token" | "other", description?: string, expiresAt?: string, metadata?: { [string]: unknown }, oauthClientId?: string, principalId?: string, refreshSecret?: string, scopes?: string[] }`
Source: packages/types/src/credentials.ts

**type**: Kind of secret material this credential holds: `api_key`, `oauth_token`, `certificate`, or `other`. Determines how `secret` (and `refreshSecret` for OAuth) is interpreted when the credential is used.
**metadata**: Free-form provider- or integration-specific data attached to the credential. Not interpreted by the hub.
**scopes**: Permissions granted to this credential by the provider (for example OAuth scopes). Informational on the credential record; the provider is the authority on what the secret can actually do.

### CreateFederationTrust
`{ direction: "bilateral" | "inbound" | "outbound", targetTenantId: string }`
Source: packages/types/src/tenants.ts

### CreateGrant
`{ action: string, effect: "allow" | "ask" | "deny", origin: "creator" | "invoker" | "role" | "system", resource: string, conditions?: { [string]: unknown } | null, expiresAt?: string | null, principalId?: string | null, roleId?: string | null }`
Source: packages/types/src/grants.ts

**effect**: Outcome when this grant is the one resolved for a request: `allow` permits the action, `deny` blocks it, `ask` requires interactive approval before proceeding. When several grants match, the most specific wins, and at equal specificity the strongest effect wins (`deny` over `ask` over `allow`).
**origin**: Records where the grant came from: `system` (built-in), `role` (granted via a role), `creator` (from the agent definition author), or `invoker` (delegated by whoever launched the agent). Origin is provenance only; it does not affect evaluation precedence.
**conditions**: Optional map of named conditions that must all pass for the grant to apply, evaluated against a condition registry at authorization time. A grant with conditions is skipped (fails closed) when no registry is available to evaluate them.

### CreateModel
`{ canonicalName: string, description?: string | null, displayName?: string | null }`
Source: packages/types/src/catalog.ts

**canonicalName**: Tenant-unique canonical model name agents match their requirements against.

### CreateModelOffering
`{ modelId: string, providerId: string, capabilities?: ("audio-input" | "audio-input-streaming" | "code-execution" | "code-execution-streaming" | "document-input" | "document-input-streaming" | "files-api-reference" | "files-api-reference-streaming" | "function-calling" | "function-calling-multi-turn" | "function-calling-multi-turn-streaming" | "function-calling-with-thinking" | "function-calling-with-thinking-streaming" | "grounding" | "grounding-streaming" | "image-output" | "image-output-streaming" | "long-context" | "plain-text" | "plain-text-streaming" | "prompt-caching" | "reasoning-content" | "reasoning-content-streaming" | "redacted-thinking" | "redacted-thinking-streaming" | "structured-output" | "structured-output-streaming" | "video-input" | "video-input-streaming" | "vision-input" | "vision-input-streaming")[], deploymentTags?: string[], priority?: number, quirks?: { [string]: unknown } }`
Source: packages/types/src/catalog.ts

**modelId**: Catalog id of a model owned by this tenant.
**providerId**: Catalog id of a model-provider owned by this tenant.
**priority**: Ordering hint for source resolution; lower values are preferred first. Defaults to 0.
**quirks**: Opaque per-deployment adapter accommodations for this offering; the adapter factory validates the provider-specific shape. Omit when the deployment needs none.

### CreateModelProvider
`{ baseURL: string, name: string, plugin: "anthropic" | "google-genai" | "openai" | "openai-compatible", credentialId?: string | null, walletId?: string | null }`
Source: packages/types/src/catalog.ts

**name**: Tenant-unique model-provider name.
**plugin**: The inference adapter that serves this provider's models, dispatched by the runtime provider registry.

### CreateOAuthClient
`{ clientId: string, clientSecret: string, name: string, providerId: string, defaultScopes?: string[], metadata?: { [string]: unknown }, redirectUris?: string[] }`
Source: packages/types/src/oauth-clients.ts

**defaultScopes**: Scopes requested by default when initiating an authorization flow with this client.
**metadata**: Free-form client-specific configuration not covered by the typed fields. Not interpreted by the hub.
**redirectUris**: Allowed OAuth redirect URIs for this client. The authorization callback must match one of these.

### CreateOffering
`{ agentId: string, name: string, description?: string, pricing?: { base?: { amount: string, currency: string }, bounds?: { max?: string, min?: string }, methods?: string[], negotiable?: boolean }, schema?: { [string]: unknown } }`
Source: packages/types/src/offerings.ts

### CreatePricingRow
`{ currency: string, cacheReadTokenPrice?: string | null, cacheWriteTokenPrice?: string | null, effectiveFrom?: string, inputTokenPrice?: string | null, outputTokenPrice?: string | null, perAudioFee?: string | null, perImageFee?: string | null, perRequestFee?: string | null, thinkingTokenPrice?: string | null }`
Source: packages/types/src/catalog.ts

**currency**: Fiat currency code or opaque credit unit this row prices in.
**cacheReadTokenPrice**: Cost per cached-read token as a decimal string in this row's `currency`, or null if this provider does not charge for it.
**cacheWriteTokenPrice**: Cost per cached-write token as a decimal string in this row's `currency`, or null if this provider does not charge for it.
**effectiveFrom**: ISO-8601 timestamp from which this price applies. Defaults to the time of the request.
**inputTokenPrice**: Cost per input token as a decimal string in this row's `currency`, or null if this provider does not charge for it.
**outputTokenPrice**: Cost per output token as a decimal string in this row's `currency`, or null if this provider does not charge for it.
**perAudioFee**: Fee per audio unit as a decimal string in this row's `currency`, or null if this provider does not charge for it.
**perImageFee**: Fee per image as a decimal string in this row's `currency`, or null if this provider does not charge for it.
**perRequestFee**: Flat fee per request as a decimal string in this row's `currency`, or null if this provider does not charge for it.
**thinkingTokenPrice**: Cost per thinking token as a decimal string in this row's `currency`, or null if this provider does not charge for it.

### CreateProvider
`{ name: string, plugin: string, apiBaseUrl?: string, authorizationUrl?: string, metadata?: { [string]: unknown }, scopes?: string[], tokenUrl?: string, userInfoUrl?: string }`
Source: packages/types/src/providers.ts

**plugin**: Identifier of the integration this provider drives (for example the inference backend). Used to dispatch to the matching plugin and as the prefix when forming fully-qualified model ids (`plugin:model`).
**apiBaseUrl**: The API origin a credential from this provider authenticates to (for example https://api.github.com). A provider that backs an origin-pinned credential must set it; OAuth-login-only providers may omit it.
**metadata**: Free-form provider-specific configuration not covered by the typed fields. Not interpreted by the hub.
**scopes**: OAuth scopes associated with this provider integration.

### CreateRole
`{ name: string, description?: string }`
Source: packages/types/src/roles.ts

### CreateTenant
`{ name: string, slug: string, parentId?: string | null }`
Source: packages/types/src/tenants.ts

### CreateWallet
`{ backendType: "credits" | "crypto" | "fiat", currency: string, name: string, config?: { [string]: unknown } }`
Source: packages/types/src/wallets.ts

**backendType**: Settlement backend the wallet is denominated in: `crypto` (on-chain assets), `fiat` (national currency), or `credits` (internal accounting units). Determines how balances and transactions are settled.
**config**: Backend-specific configuration for the wallet (for example chain or account details for a `crypto` backend). Shape depends on `backendType`; not interpreted by the hub.

### CreateWorkflowRun
`{ definitionId: string, invokerGrants?: { action: string, resource: string, conditions?: { [string]: unknown } | null, effect?: "allow" | "ask" | "deny" }[], modelPreferences?: { model: string, providers: { mode: "pin" | "prefer", order: string[] } }[] }`
Source: packages/types/src/instances.ts

**invokerGrants**: Capabilities the invoker is willing to delegate to the run, resolved against the invoker's own authority at launch. These are materialized as grants on the run principal in addition to any grants from the definition's own requirements.
**modelPreferences**: The invoker's per-model provider preferences for this launch. Applied over the tenant-visible providers after the definition's preferences; it can only reorder or restrict, never introduce a provider the tenant catalog lacks. Persisted on the run so re-resolution reuses it.

### CredentialResponse
`{ createdAt: string, id: string, name: string, providerId: string, status: "active" | "error" | "expired" | "revoked", tenantId: string, type: "api_key" | "certificate" | "oauth_token" | "other", updatedAt: string, description?: string | null, expiresAt?: string | null, metadata?: { [string]: unknown } | null, oauthClientId?: string | null, principalId?: string | null, scopes?: string[] | null }`
Source: packages/types/src/credentials.ts

**status**: Usability state of the credential: `active` (usable), `expired` (past its `expiresAt`), `revoked` (deliberately invalidated), or `error` (last use failed, e.g. rejected by the provider).
**type**: Kind of secret material this credential holds: `api_key`, `oauth_token`, `certificate`, or `other`. Determines how `secret` (and `refreshSecret` for OAuth) is interpreted when the credential is used.
**metadata**: Free-form provider- or integration-specific data attached to the credential. Not interpreted by the hub.
**scopes**: Permissions granted to this credential by the provider (for example OAuth scopes). Informational on the credential record; the provider is the authority on what the secret can actually do.

### ErrorResponse
`{ error: { code: string, message: string } }`
Source: packages/types/src/common.ts

### EvaluateRequest
`{ action: string, resource: string }`
Source: packages/types/src/grants.ts

### EvaluateResult
`{ effect: "allow" | "ask" | "deny", matchingGrants: { action: string, effect: "allow" | "ask" | "deny", id: string, origin: "creator" | "invoker" | "role" | "system", resource: string, specificity?: number }[] }`
Source: packages/types/src/grants.ts

**effect**: The resolved outcome for the query: the effect of the winning grant, or `deny` when no grant matched (authorization fails closed).
**matchingGrants**: Every grant that matched the requested resource and action, including the one that won. Useful for debugging why a request was allowed, denied, or required approval.

### FederationTrust
`{ createdAt: string, direction: "bilateral" | "inbound" | "outbound", tenantDomain: string, tenantId: string, tenantName: string }`
Source: packages/types/src/tenants.ts

### FileContent
`{ content: string, path: string, encoding?: "base64" | "utf-8" }`
Source: packages/types/src/agent-data.ts

### FileEntry
`{ path: string, type: "directory" | "file", modifiedAt?: string | null, size?: number | null }`
Source: packages/types/src/agent-data.ts

### GrantResponse
`{ action: string, createdAt: string, effect: "allow" | "ask" | "deny", id: string, origin: "creator" | "invoker" | "role" | "system", resource: string, tenantId: string, updatedAt: string, conditions?: { [string]: unknown } | null, expiresAt?: string | null, principalId?: string | null, principalName?: string | null, roleId?: string | null, roleName?: string | null }`
Source: packages/types/src/grants.ts

**effect**: Outcome when this grant is the one resolved for a request: `allow` permits the action, `deny` blocks it, `ask` requires interactive approval before proceeding. When several grants match, the most specific wins, and at equal specificity the strongest effect wins (`deny` over `ask` over `allow`).
**origin**: Records where the grant came from: `system` (built-in), `role` (granted via a role), `creator` (from the agent definition author), or `invoker` (delegated by whoever launched the agent). Origin is provenance only; it does not affect evaluation precedence.
**conditions**: Optional map of named conditions that must all pass for the grant to apply, evaluated against a condition registry at authorization time. A grant with conditions is skipped (fails closed) when no registry is available to evaluate them.

### HistoryEntry
`{ author: string, message: string, ref: string, timestamp: string, filesChanged?: number }`
Source: packages/types/src/agent-data.ts

### InviteMember
`{ email: string, roleId?: string }`
Source: packages/types/src/principals.ts

### LogEntry
`{ level: "debug" | "error" | "info" | "warn", message: string, timestamp: string, metadata?: { [string]: unknown } | null }`
Source: packages/types/src/observability.ts

### MailResponse
`{ attachments: { blobId: string, name: string | null, size: number, type: string }[], bodyValues: { [string]: unknown }, direction: "inbound" | "outbound", from: { email: string, name: string | null }[], headers: { [string]: string }, htmlBody: { partId: string, type: string }[], id: string, instanceId: string | null, receivedAt: string, sentAt: string | null, sessionId: string, status: "delivered" | "pending", subject: string | null, textBody: { partId: string, type: string }[], to: { email: string, name: string | null }[] }`
Source: packages/types/src/sessions.ts

**direction**: Whether the message was sent to the agent (`inbound`) or emitted by the agent (`outbound`).
**sessionId**: Internal session channel identifier, not a user-facing session resource.
**status**: Delivery state of the mail: `pending` (accepted, not yet dispatched to the running agent) or `delivered`.

### MetricsResponse
`{ agentId: string, avgLatencyMs?: number, cost?: string, errorRate?: number, messageCount?: number, tokenUsage?: { input?: number, output?: number, total?: number } }`
Source: packages/types/src/observability.ts

### ModelInfo
`{ canonicalName: string, id: string, offerings: { capabilities: ("audio-input" | "audio-input-streaming" | "code-execution" | "code-execution-streaming" | "document-input" | "document-input-streaming" | "files-api-reference" | "files-api-reference-streaming" | "function-calling" | "function-calling-multi-turn" | "function-calling-multi-turn-streaming" | "function-calling-with-thinking" | "function-calling-with-thinking-streaming" | "grounding" | "grounding-streaming" | "image-output" | "image-output-streaming" | "long-context" | "plain-text" | "plain-text-streaming" | "prompt-caching" | "reasoning-content" | "reasoning-content-streaming" | "redacted-thinking" | "redacted-thinking-streaming" | "structured-output" | "structured-output-streaming" | "video-input" | "video-input-streaming" | "vision-input" | "vision-input-streaming")[], deploymentTags: string[], offeringId: string, plugin: "anthropic" | "google-genai" | "openai" | "openai-compatible", pricing: { createdAt: string, currency: string, effectiveFrom: string, id: string, offeringId: string, tenantId: string, cacheReadTokenPrice?: string | null, cacheWriteTokenPrice?: string | null, inputTokenPrice?: string | null, outputTokenPrice?: string | null, perAudioFee?: string | null, perImageFee?: string | null, perRequestFee?: string | null, thinkingTokenPrice?: string | null }[], priority: number, providerId: string, providerName: string }[], description?: string | null, displayName?: string | null }`
Source: packages/types/src/models.ts

**canonicalName**: The model's tenant-unique canonical name, matched against an agent's model requirements.
**offerings**: One entry per provider that offers this model in the tenant's resolved catalog, ordered by resolution priority.

### ModelOfferingResponse
`{ capabilities: ("audio-input" | "audio-input-streaming" | "code-execution" | "code-execution-streaming" | "document-input" | "document-input-streaming" | "files-api-reference" | "files-api-reference-streaming" | "function-calling" | "function-calling-multi-turn" | "function-calling-multi-turn-streaming" | "function-calling-with-thinking" | "function-calling-with-thinking-streaming" | "grounding" | "grounding-streaming" | "image-output" | "image-output-streaming" | "long-context" | "plain-text" | "plain-text-streaming" | "prompt-caching" | "reasoning-content" | "reasoning-content-streaming" | "redacted-thinking" | "redacted-thinking-streaming" | "structured-output" | "structured-output-streaming" | "video-input" | "video-input-streaming" | "vision-input" | "vision-input-streaming")[], createdAt: string, deploymentTags: string[], disabled: boolean, id: string, modelId: string, priority: number, providerId: string, quirks: { [string]: unknown } | null, tenantId: string, updatedAt: string }`
Source: packages/types/src/catalog.ts

**capabilities**: Curated capability tags this provider advertises for this model.
**priority**: Ordering hint for source resolution; lower values are preferred first.
**quirks**: Opaque per-deployment adapter accommodations, or null when the deployment needs none.

### ModelProviderResponse
`{ baseURL: string, createdAt: string, disabled: boolean, id: string, name: string, plugin: "anthropic" | "google-genai" | "openai" | "openai-compatible", tenantId: string, updatedAt: string, credentialId?: string | null, walletId?: string | null }`
Source: packages/types/src/catalog.ts

**plugin**: The inference adapter that serves this provider's models, dispatched by the runtime provider registry.

### ModelResponse
`{ canonicalName: string, createdAt: string, disabled: boolean, id: string, tenantId: string, updatedAt: string, description?: string | null, displayName?: string | null }`
Source: packages/types/src/catalog.ts

### OAuthClientResponse
`{ createdAt: string, id: string, name: string, providerId: string, tenantId: string, updatedAt: string, defaultScopes?: string[] | null, metadata?: { [string]: unknown } | null, redirectUris?: string[] | null }`
Source: packages/types/src/oauth-clients.ts

**defaultScopes**: Scopes requested by default when initiating an authorization flow with this client.
**metadata**: Free-form client-specific configuration not covered by the typed fields. Not interpreted by the hub.
**redirectUris**: Allowed OAuth redirect URIs for this client. The authorization callback must match one of these.

### OfferingDetail
`{ agentId: string, agentName: string, id: string, name: string, tenantId: string, description?: string | null, pricing?: { base?: { amount: string, currency: string }, bounds?: { max?: string, min?: string }, methods?: string[], negotiable?: boolean }, schema?: { [string]: unknown } | null }`
Source: packages/types/src/offerings.ts

### PricingRowResponse
`{ createdAt: string, currency: string, effectiveFrom: string, id: string, offeringId: string, tenantId: string, cacheReadTokenPrice?: string | null, cacheWriteTokenPrice?: string | null, inputTokenPrice?: string | null, outputTokenPrice?: string | null, perAudioFee?: string | null, perImageFee?: string | null, perRequestFee?: string | null, thinkingTokenPrice?: string | null }`
Source: packages/types/src/catalog.ts

**currency**: Fiat currency code or opaque credit unit this row prices in.
**effectiveFrom**: ISO-8601 timestamp from which this price applies. Cost attribution at a past time uses the latest row whose effectiveFrom is at or before that time.
**cacheReadTokenPrice**: Cost per cached-read token as a decimal string in the row's `currency`, or null if this provider does not charge for it.
**cacheWriteTokenPrice**: Cost per cached-write token as a decimal string in the row's `currency`, or null if this provider does not charge for it.
**inputTokenPrice**: Cost per input token as a decimal string in the row's `currency`, or null if this provider does not charge for it.
**outputTokenPrice**: Cost per output token as a decimal string in the row's `currency`, or null if this provider does not charge for it.
**perAudioFee**: Fee per audio unit as a decimal string in the row's `currency`, or null if this provider does not charge for it.
**perImageFee**: Fee per image as a decimal string in the row's `currency`, or null if this provider does not charge for it.
**perRequestFee**: Flat fee per request as a decimal string in the row's `currency`, or null if this provider does not charge for it.
**thinkingTokenPrice**: Cost per thinking token as a decimal string in the row's `currency`, or null if this provider does not charge for it.

### PrincipalResponse
`{ createdAt: string, displayName: string, id: string, kind: "agent" | "user" | "workflow", refId: string, roles: { id: string, name: string }[], status: "active" | "deactivated" | "invited" | "suspended", tenantId: string, updatedAt: string, email?: string }`
Source: packages/types/src/principals.ts

**kind**: Whether this principal represents a `user` (a human account), an `agent`, or a `workflow` (a workflow deployment).
**refId**: Identifier of the underlying entity this principal stands for: the auth user id when `kind` is `user`, the agent id when `kind` is `agent`, or the run id when `kind` is `workflow`. Unique per tenant and kind.
**status**: Account state of the principal: `active`, `suspended`, `invited` (membership pending acceptance), or `deactivated`.

### ProviderResponse
`{ createdAt: string, id: string, name: string, plugin: string, tenantId: string, updatedAt: string, apiBaseUrl?: string | null, authorizationUrl?: string | null, metadata?: { [string]: unknown } | null, scopes?: string[] | null, tokenUrl?: string | null, userInfoUrl?: string | null }`
Source: packages/types/src/providers.ts

**plugin**: Identifier of the integration this provider drives (for example the inference backend). Used to dispatch to the matching plugin and as the prefix when forming fully-qualified model ids (`plugin:model`).
**apiBaseUrl**: The API origin a credential from this provider authenticates to (for example https://api.github.com). A provider that backs an origin-pinned credential must set it; OAuth-login-only providers may omit it.
**metadata**: Free-form provider-specific configuration not covered by the typed fields. Not interpreted by the hub.
**scopes**: OAuth scopes associated with this provider integration.

### RejectAction
`{ message?: string }`
Source: packages/types/src/approvals.ts

### RoleResponse
`{ createdAt: string, id: string, isSystem: boolean, name: string, tenantId: string, updatedAt: string, description?: string | null }`
Source: packages/types/src/roles.ts

### SendMessage
`{ content: string, attachments?: { data: string, mimeType: string, name?: string, + (undeclared): reject }[] }`
Source: packages/types/src/sessions.ts

### SessionSummary
`{ createdAt: string, definitionId: string, definitionName: string, id: string, status: "ended" | "ending" | "idle", tenantId: string, tenantName: string, lastActivityAt?: string | null }`
Source: packages/types/src/me.ts

### SpanResponse
`{ name: string, spanId: string, startTime: string, traceId: string, agentId?: string | null, attributes?: { [string]: unknown } | null, durationMs?: number | null, endTime?: string | null, parentSpanId?: string | null, status?: "error" | "ok" }`
Source: packages/types/src/observability.ts

### TenantResponse
`{ createdAt: string, domain: string, id: string, name: string, slug: string, updatedAt: string, config?: { [string]: unknown, sidecarPlacement?: { sharing: "exclusive", reuse?: "never" | "same-deployment" } }, parentId?: string | null }`
Source: packages/types/src/tenants.ts

### TraceResponse
`{ spans: { name: string, spanId: string, startTime: string, traceId: string, agentId?: string | null, attributes?: { [string]: unknown } | null, durationMs?: number | null, endTime?: string | null, parentSpanId?: string | null, status?: "error" | "ok" }[], traceId: string }`
Source: packages/types/src/observability.ts

### UpdateCredential
`{ description?: string, expiresAt?: string | null, metadata?: { [string]: unknown }, name?: string, refreshSecret?: string | null, scopes?: string[] | null, secret?: string, status?: "active" | "error" | "expired" | "revoked" }`
Source: packages/types/src/credentials.ts

**metadata**: Free-form provider- or integration-specific data attached to the credential. Not interpreted by the hub.
**scopes**: Permissions granted to this credential by the provider (for example OAuth scopes). Informational on the credential record; the provider is the authority on what the secret can actually do.
**status**: Usability state of the credential: `active` (usable), `expired` (past its `expiresAt`), `revoked` (deliberately invalidated), or `error` (last use failed, e.g. rejected by the provider).

### UpdateGrant
`{ conditions?: { [string]: unknown } | null, effect?: "allow" | "ask" | "deny", expiresAt?: string | null }`
Source: packages/types/src/grants.ts

**conditions**: Optional map of named conditions that must all pass for the grant to apply, evaluated against a condition registry at authorization time. A grant with conditions is skipped (fails closed) when no registry is available to evaluate them.
**effect**: Outcome when this grant is the one resolved for a request: `allow` permits the action, `deny` blocks it, `ask` requires interactive approval before proceeding. When several grants match, the most specific wins, and at equal specificity the strongest effect wins (`deny` over `ask` over `allow`).

### UpdateModel
`{ description?: string | null, disabled?: boolean, displayName?: string | null }`
Source: packages/types/src/catalog.ts

### UpdateModelOffering
`{ capabilities?: ("audio-input" | "audio-input-streaming" | "code-execution" | "code-execution-streaming" | "document-input" | "document-input-streaming" | "files-api-reference" | "files-api-reference-streaming" | "function-calling" | "function-calling-multi-turn" | "function-calling-multi-turn-streaming" | "function-calling-with-thinking" | "function-calling-with-thinking-streaming" | "grounding" | "grounding-streaming" | "image-output" | "image-output-streaming" | "long-context" | "plain-text" | "plain-text-streaming" | "prompt-caching" | "reasoning-content" | "reasoning-content-streaming" | "redacted-thinking" | "redacted-thinking-streaming" | "structured-output" | "structured-output-streaming" | "video-input" | "video-input-streaming" | "vision-input" | "vision-input-streaming")[], deploymentTags?: string[], disabled?: boolean, priority?: number, quirks?: { [string]: unknown } | null }`
Source: packages/types/src/catalog.ts

**quirks**: Replacement quirks bag, or null to clear it back to the adapter's default behavior. Omit to leave unchanged.

### UpdateModelProvider
`{ baseURL?: string, disabled?: boolean, name?: string }`
Source: packages/types/src/catalog.ts

### UpdateOAuthClient
`{ clientId?: string, clientSecret?: string, defaultScopes?: string[] | null, metadata?: { [string]: unknown } | null, name?: string, redirectUris?: string[] | null }`
Source: packages/types/src/oauth-clients.ts

**defaultScopes**: Scopes requested by default when initiating an authorization flow with this client.
**metadata**: Free-form client-specific configuration not covered by the typed fields. Not interpreted by the hub.
**redirectUris**: Allowed OAuth redirect URIs for this client. The authorization callback must match one of these.

### UpdateOffering
`{ description?: string, name?: string, pricing?: { base?: { amount: string, currency: string }, bounds?: { max?: string, min?: string }, methods?: string[], negotiable?: boolean }, schema?: { [string]: unknown } }`
Source: packages/types/src/offerings.ts

### UpdatePrincipal
`{ status: "active" | "deactivated" | "suspended" }`
Source: packages/types/src/principals.ts

**status**: New account state for the principal. Only `active`, `suspended`, and `deactivated` are settable; `invited` is reached only through the invitation flow.

### UpdateProvider
`{ apiBaseUrl?: string | null, authorizationUrl?: string | null, metadata?: { [string]: unknown } | null, name?: string, plugin?: string, scopes?: string[] | null, tokenUrl?: string | null, userInfoUrl?: string | null }`
Source: packages/types/src/providers.ts

**apiBaseUrl**: The API origin a credential from this provider authenticates to (for example https://api.github.com). A provider that backs an origin-pinned credential must set it; OAuth-login-only providers may omit it.
**metadata**: Free-form provider-specific configuration not covered by the typed fields. Not interpreted by the hub.
**plugin**: Identifier of the integration this provider drives (for example the inference backend). Used to dispatch to the matching plugin and as the prefix when forming fully-qualified model ids (`plugin:model`).
**scopes**: OAuth scopes associated with this provider integration.

### UpdateRole
`{ description?: string, name?: string }`
Source: packages/types/src/roles.ts

### UpdateTenant
`{ config?: { [string]: unknown, sidecarPlacement?: { sharing: "exclusive", reuse?: "never" | "same-deployment" } }, name?: string }`
Source: packages/types/src/tenants.ts

### UpdateWallet
`{ config?: { [string]: unknown }, name?: string }`
Source: packages/types/src/wallets.ts

**config**: Backend-specific configuration for the wallet (for example chain or account details for a `crypto` backend). Shape depends on `backendType`; not interpreted by the hub.

### UserProfile
`{ createdAt: string, email: string, emailVerified: boolean, id: string, name: string, updatedAt: string, image?: string | null }`
Source: packages/types/src/me.ts

### WalletResponse
`{ backendType: "credits" | "crypto" | "fiat", balance: string, createdAt: string, currency: string, id: string, name: string, tenantId: string, updatedAt: string, config?: { [string]: unknown } }`
Source: packages/types/src/wallets.ts

**backendType**: Settlement backend the wallet is denominated in: `crypto` (on-chain assets), `fiat` (national currency), or `credits` (internal accounting units). Determines how balances and transactions are settled.
**balance**: Current balance as a decimal string in the wallet's `currency`. Stored as a string to preserve precision for both crypto and fiat amounts.
**config**: Backend-specific configuration for the wallet (for example chain or account details for a `crypto` backend). Shape depends on `backendType`; not interpreted by the hub.

### WorkflowDefinitionResponse
`{ createdAt: string, currentVersion: string, id: string, name: string, status: "deployed" | "stopped", tenantId: string, updatedAt: string, description?: string | null }`
Source: packages/types/src/workflows.ts

**status**: Lifecycle state of the definition: `deployed` (a launchable version is active) or `stopped` (deactivated).

### WorkflowRollbackRequest
`{ version: string }`
Source: packages/types/src/workflows.ts

### WorkflowRunHealth
`{ liveness: "ok" | "unhealthy", readiness: "not_ready" | "ok" | "unhealthy", lastCheckedAt?: string | null }`
Source: packages/types/src/instances.ts

### WorkflowRunResponse
`{ address: string, createdAt: string, definitionId: string, definitionName: string, id: string, status: "deployed" | "error" | "running" | "stopped" | "updating", tenantId: string, updatedAt: string, endedAt?: string | null, kernelId?: string | null, publicKey?: string | null, sidecarId?: string | null }`
Source: packages/types/src/instances.ts

**status**: Lifecycle state of this run: `deployed` (provisioned on a sidecar, not yet started), `running` (started and serving), `updating` (rolling to a new definition version), `error` (launch or runtime failure), or `stopped` (undeployed).

