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

# Register Agent

> Create or update an agent instance. Registration is policy-gated based on the your organizations's `policy_mode`:
- **open** (default) — Any agent type is auto-admitted. The type is added to the
  tenant's allow-list automatically.

- **allow-list** — Only pre-approved agent types can register. Returns `403` if
  the type is not in the tenant's allow-list. Use `/agents/allow_type` to add it.

- **audit** — All types can register, but a `registration_flagged` event is
  emitted for admin review.

Auto-creates the agent-type on first registration. Tool declarations and optional MCP server configs are persisted. Requires a valid JWT Bearer token.

**Deployment mode** — `deployment_mode` selects the transport the mesh uses for every dispatch sent to this instance:

- `connected` (default) — the agent dials `connect_url` (returned in
  the response) over WebSocket and keeps the connection open; the
  mesh pushes dispatches down that socket. The agent-card probe is
  skipped. `url` must be omitted.

- `hosted` — the agent exposes a public A2A HTTP surface at `url`.
  The gateway probes `GET {url}/.well-known/agent-card.json` on
  admission; if the probe fails the registration is rejected with
  `502`.


If `deployment_mode` is omitted, the server infers `hosted` when `url` is present and `connected` otherwise.

Re-registering an existing `instance_id` with a different `deployment_mode` is rejected with `409 DEPLOYMENT_MODE_MISMATCH` — deregister first and re-register, or create a new instance.




## OpenAPI

````yaml /api-reference/openapi-bundled.yaml post /agents/register
openapi: 3.1.0
info:
  title: Svantic API
  version: 1.0.0
  description: >
    Svantic is a secured API platform that connects your existing systems to AI
    agent fleets. It supports the full agent-to-agent path—discovery,
    orchestration, governance, and knowledge—so you can ship AI-driven
    automation on a predictable foundation.

    At its core, the API streamlines multi-agent collaboration. Agents
    authenticate with client credentials, discover one another through
    A2A-compliant agent cards, and exchange messages via session-scoped
    JSON-RPC. Svantic orchestrates work across fleets, enforces guardrails and
    policies, and pairs semantic search with tamper-proof audit trails.

    The platform covers lifecycle management for agent conversations, continuous
    learning, governance with alerts and notification channels, and
    human-in-the-loop approvals — all exposed as straightforward POST-based
    APIs. You focus on domain logic inside each agent; Svantic handles
    discovery, routing, safety, and observability.
  contact:
    name: Svantic Support
    email: support@svantic.com
servers:
  - url: https://api.svantic.com
    description: Production
  - url: https://mesh.svantic.com
    description: Mesh runtime
security:
  - bearerAuth: []
tags:
  - name: Introduction
    description: >

      #### Welcome to the Svantic API

      Svantic is a production runtime for AI agent fleets. It handles discovery,
      orchestration, learning, governance, and collaboration — so you can focus
      on the domain logic inside each agent.

      #### How it works


        1. **Authenticate** — Exchange client credentials for a JWT via `POST /auth/get_token`.

        2. **Create a session** — Call `POST /sessions/init` with an `instance_id`. The gateway generates a `session_id`, extracts `tenant_id` from your JWT, and returns the session details.

        3. **Communicate** — Send messages via `POST /send` using the A2A JSON-RPC protocol. Supports both synchronous (`message/send`) and streaming (`message/stream`) responses.

        4. **Manage knowledge** — Ingest documents, run semantic searches, and track processing jobs through the Knowledge Base endpoints.

        5. **Handle approvals & human input** — When agents need human input (approvals, forms, confirmations), messages enter `input-required` state. Resolve via the dashboard, `POST /messages/{id}/resolve`, or webhook callbacks.
  - name: API Protocols & Headers
    description: >
      ## Protocols


      All Svantic API endpoints use **HTTP POST** with JSON request and response
      bodies. The only exceptions are:

      - `GET /.well-known/agent-card.json` — A2A agent card discovery

      - `GET /health` — infrastructure health check


      Streaming responses (e.g., `message/stream` via `/send`) use **Server-Sent
      Events (SSE)** over the same HTTP POST connection.


      ## Required Headers


      | Header | Value | When |

      |---|---|---|

      | `Content-Type` | `application/json` | All POST requests |

      | `Authorization` | `Bearer <jwt>` | Authenticated endpoints — all tokens
      are JWTs with scopes |


      ## JSON-RPC 2.0


      The `/send` endpoint accepts JSON-RPC 2.0 payloads. Supported methods:


      | Method | Description |

      |---|---|

      | `message/send` | Synchronous message — waits for full response |

      | `message/stream` | Streaming message — returns SSE event stream |


      Request format:

      ```json

      {
        "jsonrpc": "2.0",
        "id": "req-001",
        "method": "message/send",
        "params": {
          "message": {
            "kind": "message",
            "messageId": "msg-001",
            "role": "user",
            "parts": [{ "kind": "text", "text": "Your prompt here" }]
          }
        }
      }

      ```
  - name: Environments
    description: >

      | Environment | Base URL | Description |

      |---|---|---|

      | **Production** | `https://api.svantic.com` | Live production environment
      |
  - name: Credentials & Access
    description: >

      ### Authentication


      All authenticated requests use `Authorization: Bearer <jwt>`. There is a
      single token format — a JWT signed by the gateway.


      #### Obtaining a token


      Exchange client credentials for a JWT via `POST /auth/get_token`:


      ```bash

      curl -X POST https://api.svantic.com/auth/get_token \
        -H "Content-Type: application/json" \
        -d '{"client_id": "your-credential-id", "client_secret": "your-secret", "agent_type": "my-agent"}'
      ```


      The response contains a `token` field — a JWT valid for 24 hours. Use it
      in subsequent requests:


      ```bash

      curl -X POST https://api.svantic.com/sessions/init \
        -H "Authorization: Bearer eyJ..." \
        -H "Content-Type: application/json" \
        -d '{"instance_id": "inst-001"}'
      ```


      ### Callback Token


      Outbound webhook notifications include a single-use, time-limited
      `callback_token`. External systems resolve pending messages via `POST
      /messages/{id}/resolve` by passing this token in the request body — no JWT
      required. Authenticated callers use a JWT instead.
  - name: Versioning
    description: >
      ## API Versioning


      The Svantic API is currently at **v1.0.32**. All endpoints are unversioned
      in the URL path.


      ### Stability Guarantees


      - **Stable endpoints** (Auth, Agents, Sessions, Knowledge Base): Breaking
      changes will be communicated with at least 30 days notice and a migration
      guide.

      - **Experimental endpoints** : May change without notice. Marked with
      `x-experimental: true` in the spec when applicable.


      ### Deprecation Policy


      Deprecated endpoints return a `Deprecation` header with the sunset date.
      They continue to function until the sunset date, after which they return
      `410 Gone`.
  - name: Endpoints
    description: >
      ## Endpoint Conventions


      All Svantic API endpoints follow these conventions:


      - **HTTP Method**: All operations use `POST` unless explicitly stated
      otherwise.

      - **Request bodies**: JSON. Identifiers are passed in the body, not in the
      URL path

      - **Response format**: JSON with consistent envelope (`ok`, `error`,
      resource-specific fields)


      ### Error Responses


      All errors follow a consistent format:


      ```json

      {
        "error": "Human-readable error message",
        "code": "MACHINE_READABLE_CODE"
      }

      ```


      ### Common HTTP Status Codes


      | Code | Meaning |

      |---|---|

      | `200` | Success |

      | `400` | Validation error — missing or invalid fields |

      | `401` | Authentication failed — missing, invalid, or expired credentials
      |

      | `403` | Insufficient scope — JWT scopes do not include required
      permission |

      | `404` | Resource not found |

      | `409` | Conflict — duplicate or already-processed resource |

      | `410` | Gone — expired resource (e.g., callback token) |

      | `500` | Internal server error — unexpected error in the application code
      |

      | `502` | Upstream service unavailable (e.g., Knowledge Service, LLM
      provider) |

      | `503` | Service not configured due to internal configuration error |


      ### Async Operations & Job Tracking


      Several operations (ingest, refresh, create) may run asynchronously for
      large payloads. These endpoints return a `job_id` with an initial `status`
      of `"processing"`. Poll `POST /knowledge_base/get_status` with the
      `job_id` until `status` is `"completed"` or `"failed"`.


      When an agent needs human input, the message enters `input-required`
      state. Authenticated callers resolve via `POST /messages/{id}/resolve`
      with a JWT. External systems that received a webhook notification resolve
      via the same endpoint using a `callback_token` in the request body — no
      JWT required.
  - name: Agents
    description: >-
      Purpose: connect your running agents to Svantic so they are discoverable,
      eligible for orchestration, and aligned with your access rules—this is the
      resource you use to bring your fleet into the platform and keep that
      picture current.
  - name: Messages
    description: >-
      The unified resource for all agent interactions. Send messages via A2A
      JSON-RPC (`POST /send`), query message history (`/messages/get`,
      `/messages/get_by_id`), cancel running messages (`/messages/cancel`), list
      those awaiting human input (`/messages/pending`), and submit resolutions
      (`/messages/{id}/resolve`). Every message belongs to a session and tracks
      the full lifecycle — submitted, working, input-required, completed,
      failed, or canceled.
  - name: Sessions
    description: >-
      Session lifecycle — create (`init`), close, and interrupt — plus query
      endpoints for listing sessions and retrieving session detail. Pending work
      within sessions (approvals, human input) is managed via the Messages
      resource (`/messages/pending`, `/messages/{id}/resolve`).
  - name: Knowledge Base
    description: >
      Knowledge base management — CRUD, document ingest, semantic search,
      embedding refresh, and job status tracking. All knowledge operations go
      through the gateway (`POST /knowledge_base/*`); there is no separate
      direct-to-backend path for callers. The gateway validates the JWT and
      routes requests downstream with the caller's token context. All endpoints
      require JWT authentication via `Authorization: Bearer <jwt>`. Read
      operations (list, get, query, stats) require `read` scope or higher.
      Mutations (create, update, delete, ingest, refresh) require `full` scope.
  - name: Policies
    description: >
      Guard policies control what agents can do — tool access, admission,
      dispatch. Alert rules define when and where the platform sends
      notifications, with inline notification targets using built-in channel
      types (webhook, Slack, email). To permanently allow a previously blocked
      tool, update the policy decision. All endpoints require `admin` scope.
  - name: Telemetry
    description: >
      Read-only telemetry data — traces, usage statistics, events, and real-time
      event streaming. Provides observability into agent fleet activity for
      dashboards and monitoring. All endpoints require `read` scope.
  - name: Webhooks
    description: >
      Svantic sends outbound webhooks to notify your systems when significant
      events occur. Webhooks are **outbound only** — Svantic pushes event
      payloads to URLs you configure as notification channels.


      To receive webhooks, register a webhook notification channel via the
      dashboard or API, then attach it to an alert rule or policy. When a
      matching event fires, Svantic delivers a signed JSON payload to your
      endpoint.


      ### Delivery


      - **Method**: `POST` with `Content-Type: application/json`

      - **Retries**: Up to 3 attempts with exponential backoff (1s, 5s, 30s)

      - **Timeout**: 10 seconds per attempt

      - **Idempotency**: Each delivery includes a unique `delivery_id`; use it
      to deduplicate

      - **Success**: Any `2xx` response is treated as successful delivery

      - **Client errors**: `4xx` responses stop retries immediately (no point
      retrying a bad endpoint)

      - **Server errors**: `5xx` responses trigger retries


      ### Signature Verification


      Every outbound webhook includes an `X-Svantic-Signature` header containing
      an HMAC-SHA256 signature computed over the raw request body using the
      channel's configured `secret`. To verify:


      ```typescript

      import { createHmac, timingSafeEqual } from "node:crypto";

      const expected = createHmac("sha256",
      secret).update(rawBody).digest("hex");

      const valid = timingSafeEqual(Buffer.from(expected),
      Buffer.from(req.headers["x-svantic-signature"]!));

      ```


      ### Event Categories


      Svantic emits webhook notifications for events across these categories:


      | Category | Description | |---|---| | `agent` | Agent lifecycle —
      registration, health changes, capacity | | `session` | Session creation
      and closure | | `dispatch` | Work dispatched to agents — success or
      failure | | `message` | Message lifecycle — received, completed, errors |
      | `policy` | Policy evaluation outcomes — denied, approval required | |
      `guard` | Guard decisions — allowed, denied, approval required | | `plan`
      | Execution plans — created, approved, completed, failed | | `system` |
      Platform events — alerts triggered | | `tenant` | Tenant lifecycle —
      created, deleted |


      ### Webhook Payload Schema


      Every webhook delivery uses this envelope:


      ```json

      {
        "delivery_id": "d-a1b2c3d4",
        "event_type": "agent.health_changed",
        "timestamp": "2026-04-17T14:30:00.000Z",
        "tenant_id": "tenant-abc",
        "session_id": "sess-123",
        "rule_name": "Agent unhealthy",
        "severity": "critical",
        "type": "alert",
        "event": { },
        "callback_token": "rAnDoM_base64url_token",
        "resolve_url": "https://api.svantic.com/messages/{id}/resolve"
      }

      ```


      | Field | Type | Description | |---|---|---| | `delivery_id` | string |
      Unique identifier for this delivery attempt (for idempotency) | |
      `event_type` | string | The specific event that triggered this webhook
      (e.g., `agent.health_changed`) | | `timestamp` | string (ISO 8601) | When
      the event occurred | | `tenant_id` | string | Tenant that owns the
      resource | | `session_id` | string | Session context (empty string if not
      session-scoped) | | `rule_name` | string | Name of the alert rule or
      policy that matched | | `severity` | string | `info`, `warning`, or
      `critical` | | `type` | string | `alert` for event notifications,
      `approval_required` for human-in-the-loop | | `event` | object |
      Event-specific data (see per-event schemas below) | | `callback_token` |
      string | Single-use token for resolving approval requests without JWT auth
      | | `resolve_url` | string | URL to POST resolution to (only present for
      `approval_required` type) |


      ### Event Types Reference


      #### Agent Events


      **`agent.registered`** — An agent instance registered with the platform.

      ```json

      { "agent_type": "my-agent", "instance_id": "inst-001", "tenant_id":
      "tenant-abc", "connect_mode": "connected" }

      ```


      **`agent.deregistered`** — An agent instance was removed (explicit
      deregistration or reaped for inactivity).

      ```json

      { "agent_type": "my-agent", "instance_id": "inst-001", "reason":
      "explicit" }

      ```


      **`agent.health_changed`** — An agent's health status transitioned.

      ```json

      { "agent_type": "my-agent", "instance_id": "inst-001", "status":
      "unhealthy", "previous_status": "available" }

      ```


      **`agent.capacity_changed`** — An agent's session capacity changed.

      ```json

      { "agent_type": "my-agent", "instance_id": "inst-001", "current_sessions":
      5, "max_concurrent_sessions": 10 }

      ```


      #### Session Events


      **`session.created`** — A new session was initialized.

      ```json

      { "session_id": "sess-123", "tenant_id": "tenant-abc", "created_by":
      "inst-001" }

      ```


      **`session.closed`** — A session was closed.

      ```json

      { "session_id": "sess-123", "reason": "user_closed", "duration_ms": 45000
      }

      ```


      #### Dispatch Events


      **`dispatch.sent`** — Work was dispatched to an agent.

      ```json

      { "dispatch_id": "d-001", "instance_id": "inst-001", "skill_id":
      "summarize", "session_id": "sess-123" }

      ```


      **`dispatch.success`** — A dispatch completed successfully.

      ```json

      { "dispatch_id": "d-001", "instance_id": "inst-001", "duration_ms": 1200 }

      ```


      **`dispatch.failed`** — A dispatch failed.

      ```json

      { "dispatch_id": "d-001", "instance_id": "inst-001", "error": "timeout",
      "duration_ms": 30000 }

      ```


      #### Message Events


      **`message.received`** — A user message was received.

      ```json

      { "message_id": "msg-001", "session_id": "sess-123", "role": "user" }

      ```


      **`message.completed`** — An agent response was delivered.

      ```json

      { "message_id": "msg-002", "session_id": "sess-123", "role": "agent",
      "duration_ms": 3400 }

      ```


      **`message.error`** — A message processing error occurred.

      ```json

      { "message_id": "msg-001", "session_id": "sess-123", "error": "LLM
      provider timeout" }

      ```


      #### Policy & Guard Events


      **`policy.denied`** — A policy denied an action.

      ```json

      { "policy_id": "pol-001", "policy_name": "No PII export", "action":
      "tool_call", "tool": "export_csv", "reason": "PII detected" }

      ```


      **`policy.approval_required`** — A policy requires human approval before
      proceeding.

      ```json

      { "policy_id": "pol-001", "policy_name": "High-value actions", "action":
      "tool_call", "tool": "delete_records", "message_id": "msg-001",
      "session_id": "sess-123" }

      ```


      **`guard.denied`** — A guard blocked an operation.

      ```json

      { "guard": "resource_budget", "action": "tool_call", "tool":
      "batch_delete", "reason": "Budget exceeded" }

      ```


      **`guard.approval_required`** — A guard requires approval.

      ```json

      { "guard": "file_access", "action": "tool_call", "tool": "read_file",
      "path": "/etc/config", "message_id": "msg-001" }

      ```


      #### Plan Events


      **`plan.created`** — An execution plan was generated.

      ```json

      { "plan_id": "plan-001", "session_id": "sess-123", "step_count": 4,
      "description": "Research and summarize quarterly results" }

      ```


      **`plan.approved`** — A plan was approved for execution.

      ```json

      { "plan_id": "plan-001", "approved_by": "user@example.com" }

      ```


      **`plan.completed`** — A plan finished executing.

      ```json

      { "plan_id": "plan-001", "session_id": "sess-123", "steps_completed": 4,
      "duration_ms": 120000 }

      ```


      **`plan.failed`** — A plan failed during execution.

      ```json

      { "plan_id": "plan-001", "session_id": "sess-123", "failed_step": 3,
      "error": "Agent timeout on step 'analyze'" }

      ```


      #### System Events


      **`system.alert_triggered`** — A system-level alert rule fired.

      ```json

      { "rule_id": "rule-001", "rule_name": "High error rate", "threshold": 5,
      "window_seconds": 300, "count": 7 }

      ```


      **`tenant.created`** — A new tenant was provisioned.

      ```json

      { "tenant_id": "tenant-new", "name": "Acme Corp" }

      ```


      ### Approval Webhooks


      When a policy or guard requires human approval, the webhook payload uses
      `type: "approval_required"` and includes `callback_token` and
      `resolve_url`. Your system can resolve the request by POSTing back:


      ```bash

      curl -X POST https://api.svantic.com/messages/msg-001/resolve \
        -H "Content-Type: application/json" \
        -d '{"callback_token": "rAnDoM_base64url_token", "resolution": "approved"}'

      ```


      The `callback_token` is single-use, time-limited (default 24 hours), and
      does not require JWT authentication. See the [Long-Running Operations
      Guide](/guides/long-running-operations) for details.


      ### Configuring Webhooks


      Webhook channels are managed through the notification channels API or the
      dashboard:


      1. Create a webhook channel with your endpoint URL and optional HMAC
      secret

      2. Attach the channel to an alert rule or policy

      3. Svantic delivers matching events to your endpoint with signature
      verification


      All deliveries are logged with status code, response time, and
      success/failure for audit and debugging.
paths:
  /agents/register:
    post:
      tags:
        - Agents
      summary: Register Agent
      description: >
        Create or update an agent instance. Registration is policy-gated based
        on the your organizations's `policy_mode`:

        - **open** (default) — Any agent type is auto-admitted. The type is
        added to the
          tenant's allow-list automatically.

        - **allow-list** — Only pre-approved agent types can register. Returns
        `403` if
          the type is not in the tenant's allow-list. Use `/agents/allow_type` to add it.

        - **audit** — All types can register, but a `registration_flagged` event
        is
          emitted for admin review.

        Auto-creates the agent-type on first registration. Tool declarations and
        optional MCP server configs are persisted. Requires a valid JWT Bearer
        token.


        **Deployment mode** — `deployment_mode` selects the transport the mesh
        uses for every dispatch sent to this instance:


        - `connected` (default) — the agent dials `connect_url` (returned in
          the response) over WebSocket and keeps the connection open; the
          mesh pushes dispatches down that socket. The agent-card probe is
          skipped. `url` must be omitted.

        - `hosted` — the agent exposes a public A2A HTTP surface at `url`.
          The gateway probes `GET {url}/.well-known/agent-card.json` on
          admission; if the probe fails the registration is rejected with
          `502`.


        If `deployment_mode` is omitted, the server infers `hosted` when `url`
        is present and `connected` otherwise.


        Re-registering an existing `instance_id` with a different
        `deployment_mode` is rejected with `409 DEPLOYMENT_MODE_MISMATCH` —
        deregister first and re-register, or create a new instance.
      operationId: agents_register
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/agent_register_request'
            examples:
              sample:
                $ref: '#/components/examples/agents_register_request'
      responses:
        '200':
          description: Agent registered successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/agent_register_response'
              examples:
                sample:
                  $ref: '#/components/examples/agents_register_response_200'
        '400':
          $ref: '#/components/responses/bad_request'
        '401':
          $ref: '#/components/responses/unauthorized'
        '403':
          $ref: '#/components/responses/forbidden'
        '404':
          $ref: '#/components/responses/not_found'
        '408':
          $ref: '#/components/responses/request_timeout'
        '409':
          description: >
            `DEPLOYMENT_MODE_MISMATCH` — an instance with this `instance_id`
            already exists under a different `deployment_mode`. Deregister and
            re-register, or use a new `instance_id`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/error_response'
        '500':
          $ref: '#/components/responses/internal_error'
        '502':
          $ref: '#/components/responses/bad_gateway'
        '503':
          $ref: '#/components/responses/service_unavailable'
components:
  schemas:
    agent_register_request:
      type: object
      required:
        - agent_type
        - instance_id
      properties:
        agent_type:
          type: string
          description: Logical agent type (e.g. "navigator", "transcript-link").
        instance_id:
          type: string
          description: Unique instance id (caller-supplied; upserted per instance).
        url:
          type:
            - string
            - 'null'
          format: uri
          description: >
            Base URL where the agent serves its A2A surface. Required for
            `hosted` mode; must be omitted or `null` for `connected` mode.
            Switching the deployment_mode for an existing instance is rejected
            with `409 DEPLOYMENT_MODE_MISMATCH`.
        deployment_mode:
          type: string
          enum:
            - hosted
            - connected
          default: connected
          description: >
            How the mesh reaches this agent for dispatches.

            - `connected` (default) — mesh pushes frames down an
              agent-initiated WebSocket. Works anywhere outbound HTTPS/WSS
              reaches, including behind firewalls, NATs, laptops, and CI.
            - `hosted` — mesh POSTs to `url` over HTTPS. Opt in when your
              agent already runs as a public HTTP service.

            If the field is omitted, the server infers `hosted` when `url` is
            present and `connected` otherwise.
        dispatch_auth:
          $ref: '#/components/schemas/agent_dispatch_auth'
        dispatch_auth_shared_secret:
          type: string
          minLength: 1
          maxLength: 4096
          writeOnly: true
          description: >
            Raw secret bytes for `dispatch_auth.type=shared_secret`. Required on
            register when and only when `dispatch_auth.type` is `shared_secret`;
            rejected with 400 in any other case. The gateway encrypts this value
            under the tenant key and stores the ciphertext in
            `agent_instances.dispatch_auth_secret_ciphertext`; the raw value is
            never echoed in any response. Rotate by re-registering with a new
            `credentials_ref` and a fresh secret.
        agent_card:
          type: object
          additionalProperties: true
          default: {}
          description: Optional agent card JSON persisted with the instance.
        tools:
          type: array
          items:
            $ref: '#/components/schemas/agent_tool'
          default: []
          description: >-
            Dynamic tool declarations registered with this instance. These are
            instance-specific capabilities that may vary across instances of the
            same agent type.
        mcp_servers:
          type: object
          additionalProperties:
            type: object
            required:
              - command
            properties:
              command:
                type: string
              args:
                type: array
                items:
                  type: string
                default: []
          description: >-
            Optional MCP server configs applied to the agent type for this
            tenant.
    agent_register_response:
      type: object
      description: >
        Registration confirmation. The `tenant_id` is derived from the JWT.

        Connected-mode agents must dial the returned `connect_url` over
        WebSocket immediately and keep the connection open; that socket is the
        only path dispatches reach the agent on. Hosted-mode agents can ignore
        `connect_url` (it is `null`).
      required:
        - ok
        - tenant_id
        - instance_id
        - deployment_mode
      properties:
        ok:
          type: boolean
        tenant_id:
          type: string
          description: Tenant derived from the JWT Bearer token.
        instance_id:
          type: string
          description: Echo of the submitted instance_id, confirming the upsert target.
        deployment_mode:
          type: string
          enum:
            - hosted
            - connected
          description: >
            The effective deployment mode for this instance after admission.
            Usually matches the request, but the server may reject a switch
            attempt with `409 DEPLOYMENT_MODE_MISMATCH` (see the register path
            spec), so callers should always trust this value.
        connect_url:
          type:
            - string
            - 'null'
          format: uri
          description: >
            Populated only for `connected` mode: the WebSocket endpoint the SDK
            must dial to complete registration. Always includes the
            `instance_id` as a query parameter; authenticate with the same JWT
            used for the register call. `null` for `hosted` mode.
        svantic_jwks_url:
          type:
            - string
            - 'null'
          format: uri
          description: >
            Public JWKS endpoint for `dispatch_auth.type = svantic_jwt`
            validation. `null` when the agent declared a non-JWT auth scheme.
            Hosted agents that rely on the default scheme should cache this JWKS
            with a short TTL (max 10 minutes) to catch signing-key rotations.
        dispatch_auth:
          $ref: '#/components/schemas/agent_dispatch_auth'
    error_response:
      type: object
      required:
        - error
      properties:
        error:
          type: string
          description: Human-readable error message.
        code:
          type: string
          description: Machine-readable error code, when available.
        request_id:
          type: string
          description: >
            Correlation id for support — present on some gateway catch-all
            responses (e.g. unmatched route, unhandled error).
        timestamp:
          type: string
          format: date-time
          description: >-
            ISO 8601 time when the error was produced, when returned by the
            gateway.
    agent_dispatch_auth:
      type: object
      description: >
        How the mesh authenticates each dispatch it sends to the agent.

        Per-dispatch authentication applies to **both** `hosted` (HTTPS
        callback) and `connected` (WebSocket) agents. The envelope is attached
        to every outbound dispatch payload and verified by the SDK on the agent
        side via `verify_dispatch_auth`.

        Enforcement is gated by the mesh's `SVANTIC_DISPATCH_AUTH_ENABLED` flag.
        When the flag is on, the mesh refuses to send unauthenticated
        dispatches; when off, the mesh skips minting envelopes and the SDK skips
        verification. Both sides must agree on the flag.

        Defaults to `svantic_jwt` when omitted.

        See the internal spec `platform/docs/specs/dispatch_auth.md` for the
        wire format, error taxonomy, and test ownership.
      required:
        - type
      properties:
        type:
          type: string
          enum:
            - svantic_jwt
            - shared_secret
            - mtls
          description: |
            Authentication scheme the mesh mints on each dispatch.
            - `svantic_jwt` (default) — mesh mints a short-lived HS256 JWT
              signed with `SIGNING_SECRET`. The SDK verifies against the
              same secret. Rotation = rotate the secret; no per-agent
              state.
            - `shared_secret` — mesh looks up a tenant-supplied raw secret
              by `credentials_ref`, attaches it to the envelope, and the
              SDK compares against its local copy. Use when the agent
              must prove possession of a secret the tenant minted
              themselves (e.g. the agent forwards dispatches to a legacy
              system that already speaks a shared-secret protocol).
            - `mtls` — reserved, not implemented.
        credentials_ref:
          type:
            - string
            - 'null'
          default: null
          description: >
            Opaque vault reference (`vault://…` URI) to the raw secret.

            Required when `type` is `shared_secret`; must be omitted when `type`
            is `svantic_jwt` or `mtls`. The raw secret itself is supplied only
            at registration time via `dispatch_auth_shared_secret` (never echoed
            in responses and never reachable over the public API once stored).
    agent_tool:
      type: object
      description: >-
        A dynamic tool registered by an agent instance at runtime. Tools are
        instance-specific capabilities that may vary across instances of the
        same agent type.
      required:
        - name
      properties:
        name:
          type: string
          description: Unique identifier for the tool within the instance
          example: execute_command
        description:
          type: string
          description: Human-readable description of what the tool does
          example: Executes a shell command in the terminal
        inputSchema:
          type: object
          description: JSON Schema defining the tool's input parameters
          additionalProperties: true
          example:
            type: object
            properties:
              command:
                type: string
                description: The command to execute
            required:
              - command
  examples:
    agents_register_request:
      summary: Sample request body for agents register (connected — default)
      value:
        agent_type: navigator
        instance_id: navigator-prod-01
        deployment_mode: connected
        dispatch_auth:
          type: svantic_jwt
        agent_card:
          example_key: example_value
        tools:
          - example_key: example_value
        mcp_servers:
          sample_key:
            command: string
            args:
              - string
    agents_register_response_200:
      summary: Sample 200 response for agents register (connected — default)
      value:
        ok: true
        tenant_id: tenant_abc123
        instance_id: navigator-prod-01
        deployment_mode: connected
        connect_url: wss://api.svantic.com/agents/connect
        svantic_jwks_url: https://api.svantic.com/.well-known/jwks.json
        dispatch_auth:
          type: svantic_jwt
    error_bad_request_example:
      summary: Validation or malformed JSON body
      value:
        error: Invalid request body
        code: BAD_REQUEST
    error_unauthorized_example:
      summary: Authentication failed
      value:
        error: Invalid or expired token
        code: unauthorized
    error_forbidden_example:
      summary: Insufficient scope
      value:
        error: JWT does not include the required scope for this operation
        code: forbidden
    error_not_found_example:
      summary: Resource or route not found
      value:
        error: Not found
        code: NOT_FOUND
        request_id: req_01EXAMPLE
        timestamp: '2026-03-31T12:00:00.000Z'
    error_request_timeout_example:
      summary: Client or gateway request timeout
      value:
        error: Request timeout
        code: REQUEST_TIMEOUT
    error_internal_example:
      summary: Unhandled gateway error
      value:
        error: Internal server error
        code: INTERNAL_ERROR
        request_id: req_01EXAMPLE
        timestamp: '2026-03-31T12:00:00.000Z'
    error_bad_gateway_example:
      summary: Upstream or proxy failure
      value:
        error: Bad gateway
        code: BAD_GATEWAY
    error_service_unavailable_example:
      summary: Dependency or signing unavailable
      value:
        error: Service temporarily unavailable
        code: SERVICE_UNAVAILABLE
  responses:
    bad_request:
      description: >
        Malformed JSON, failed request validation, or missing required fields in
        the body (gateway returns before the handler runs in some cases).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/error_response'
          examples:
            sample:
              $ref: '#/components/examples/error_bad_request_example'
    unauthorized:
      description: Authentication failed — missing or invalid credentials.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/error_response'
          examples:
            sample:
              $ref: '#/components/examples/error_unauthorized_example'
    forbidden:
      description: >-
        Insufficient scope — JWT does not carry the required scope for this
        operation.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/error_response'
          examples:
            sample:
              $ref: '#/components/examples/error_forbidden_example'
    not_found:
      description: >
        Unknown resource identifier, tenant mismatch for the requested resource,
        or (for unmatched HTTP routes) the gateway catch-all `NOT_FOUND`
        envelope.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/error_response'
          examples:
            sample:
              $ref: '#/components/examples/error_not_found_example'
    request_timeout:
      description: |
        Request exceeded the gateway timeout window (HTTP 408).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/error_response'
          examples:
            sample:
              $ref: '#/components/examples/error_request_timeout_example'
    internal_error:
      description: >
        Unhandled exception in the gateway — `INTERNAL_ERROR` with optional
        `request_id` and `timestamp` for correlation.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/error_response'
          examples:
            sample:
              $ref: '#/components/examples/error_internal_example'
    bad_gateway:
      description: >
        Gateway received an invalid or failed response from an upstream
        dependency (MCP Servers, Mesh, Gateway, etc.), or could not complete a
        proxied request.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/error_response'
          examples:
            sample:
              $ref: '#/components/examples/error_bad_gateway_example'
    service_unavailable:
      description: >
        Temporary failure — e.g. JWT signing not configured (`MESH_SECRET`
        missing on token route), mesh or upstream unreachable, or dependency
        unavailable.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/error_response'
          examples:
            sample:
              $ref: '#/components/examples/error_service_unavailable_example'

````