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

# Liveness + readiness probe

> Returns 200 when healthy, 503 when any mandatory dependency
(storage, scheduler, message bus, grpc) is degraded. The body
carries per-component status so orchestrators can show which
specific thing is broken.




## OpenAPI

````yaml /openapi.yaml get /health
openapi: 3.1.0
info:
  title: Bindu Agent API
  version: 1.0.0
  summary: >-
    A2A-protocol compliant agent API with DID identity, OAuth2 authentication,
    and x402 payments
  x-logo:
    url: https://docs.getbindu.com/logo/light.svg
    altText: Bindu Logo
  description: >
    # The Bindu Agent API


    Every Bindu agent speaks the same HTTP API. You don't write the

    routes — [`bindufy()`](https://docs.getbindu.com/bindu/reference/bindufy)

    wires them up for you. This spec is the same across every agent,

    no matter what it does. A weather agent and a stock agent both

    answer to these exact endpoints.


    What makes a given agent unique is its *handler* (the function you

    wrote). The API shape around it stays identical.


    ---


    ## One endpoint, many methods


    Here's the first thing to know: almost every call goes to `POST /`.


    You don't hit `/tasks/123`. You don't hit `/messages/send`. You

    POST a JSON-RPC body to `/`, and the `method` field inside the

    body tells the agent what you want.


    | Method | What it does |

    |---|---|

    | `message/send` | Kick off work. You get back a `Task` object. |

    | `message/stream` | *(Experimental)* SSE stream of task deltas. |

    | `tasks/get` | Poll a task by id until it finishes. |

    | `tasks/list` | See the caller's recent tasks. |

    | `tasks/cancel` | Stop a running task. |

    | `tasks/feedback` | Rate a completed task. |

    | `tasks/pushNotificationConfig/set` | Register a webhook for task updates.
    |

    | `tasks/pushNotificationConfig/get` | Read the webhook registered for a
    task. |

    | `tasks/pushNotificationConfig/list` | List webhook configs for a task. |

    | `tasks/pushNotificationConfig/delete` | Remove a webhook from a task. |

    | `contexts/list` | See active conversation contexts. |

    | `contexts/clear` | Reset a context. |


    A few auxiliary things — skills, DID resolution, negotiation,

    payment — use normal REST paths. You'll find them in the *Paths*

    section below.


    ---


    ## Everything is a Task


    Send a message, and you get a **Task** with a unique id. Think of

    it like a receipt — it's the thing you track. Even for quick

    one-shot answers, there's a task behind the scenes.


    Why build it this way?


    - **Tasks don't block.** Some work takes seconds, some takes
      minutes. Polling a task id works for both. You never have to
      hold an HTTP connection open for 10 minutes.
    - **Tasks chain together.** Pass `referenceTaskIds` on a new
      `message/send` and the new task can read the earlier task's
      output. Great for "take that result and summarize it."
    - **Tasks share context.** Reuse the same `contextId` across
      calls and the agent keeps the conversation going.
    - **Tasks have clear states.** You always know exactly where the
      work is — queued, running, waiting, done, or failed.

    ### The states a task can be in


    **Still going:**

    - `submitted` — queued, waiting for a worker to pick it up

    - `working` — actively being processed right now

    - `input-required` — paused; the agent has a question for you

    - `auth-required` — paused; waiting for an auth flow


    **Finished (and frozen — can't be resumed):**

    - `completed` — success. Your answer is in `artifacts`.

    - `failed` — something broke. Check `status.message` for why.

    - `canceled` — someone called `tasks/cancel`.

    - `rejected` — the agent declined to handle it. Reason in `status.message`.


    Once a task is in a terminal state, it's immutable. If you want

    to refine a completed answer, start a new `message/send` and pass

    `referenceTaskIds: [<old-task-id>]`. The new task can read the

    old one's artifacts and build on them.


    ---


    ## Authentication


    Bindu supports three layers of auth. Most clients only need the

    first one.


    ### Layer 1 — Bearer token (required for anything that writes)


    Every request that changes state needs an OAuth2 token from Ory

    Hydra in the `Authorization` header:


    ```

    Authorization: Bearer <hydra-issued access token>

    ```


    The server introspects the token on every request. The scope in

    the token decides what you can do:


    | Scope | What it unlocks |

    |---|---|

    | `agent:read` | `tasks/get`, `tasks/list`, `contexts/list`, all `GET`
    endpoints |

    | `agent:write` | `message/send`, `tasks/cancel`, `tasks/feedback`,
    `contexts/clear` |


    (`agent:execute` is a legacy scope that implies both — new code

    should use the specific ones.)


    ### Layer 2 — DID signatures (optional, for agent-to-agent calls)


    When your agent is calling another agent, you can sign the

    request with your DID private key. That lets the other side

    verify it's really you on the line, not just someone with your

    token.


    Three headers do the work:


    | Header | Value |

    |---|---|

    | `X-DID` | Your full DID string |

    | `X-DID-Timestamp` | Unix seconds (must be within ±300s of the server's
    clock) |

    | `X-DID-Signature` | base58 of an Ed25519 signature over the payload |


    The signature payload is Python's

    `json.dumps({"body": body, "did": did, "timestamp": ts}, sort_keys=True)`.

    Heads up: Python's default separators include spaces after `:`

    and `,`. The body has to be the exact UTF-8 bytes you sent —

    if any middleware re-serializes it, your signature stops

    matching and the server returns `reason: "crypto_mismatch"`.


    What the server checks, in order:

    1. Introspect the bearer token — `client_id` must start with `did:`.

    2. The `X-DID` header must equal the token's `client_id`.

    3. Hydra metadata for that client must have a `public_key` set.

    4. Verify the Ed25519 signature, and check the timestamp is in window.


    Full walk-through (including the common ways this goes wrong) is

    in the [DID guide](https://docs.getbindu.com/bindu/learn/did/overview).


    ### Layer 3 — x402 payment (only for paid endpoints)


    If the agent charges for a request, send a base64-encoded x402

    payload as the `X-PAYMENT` header on `message/send`. Or — for

    repeated calls — open a session first with

    `POST /api/start-payment-session` and attach the session handle

    to subsequent requests.


    ---


    ## Errors


    Errors always come back in the JSON-RPC envelope:


    ```json

    { "jsonrpc": "2.0", "id": "...", "error": { "code": ..., "message": "...",
    "data": { ... } } }

    ```


    Three groups of codes, all documented here so you know what

    you're looking at.


    ### Standard JSON-RPC (straight from the RFC)


    | Code | Name | HTTP | When you'll see it |

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

    | `-32700` | Parse error | 400 | Body isn't valid JSON at all |

    | `-32600` | Invalid Request | 400 | Body is JSON but not a valid JSON-RPC
    request |

    | `-32601` | Method not found | 404 | The `method` name isn't one this agent
    supports |

    | `-32602` | Invalid params | 400 | `params` failed schema validation |

    | `-32603` | Internal error | 500 | Server bug — file a GitHub issue |


    ### A2A protocol


    | Code | Name | HTTP | When you'll see it |

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

    | `-32001` | TaskNotFound | 404 | `taskId` doesn't exist, or isn't yours |

    | `-32002` | TaskNotCancelable | 400 | The task is already in a terminal
    state |

    | `-32003` | PushNotificationNotSupported | 400 | This agent doesn't do push
    notifications |

    | `-32004` | UnsupportedOperation | 400 | e.g. `message/stream` on a
    non-streaming agent |

    | `-32005` | ContentTypeNotSupported | 400 | `acceptedOutputModes` doesn't
    match what the agent can produce |

    | `-32006` | InvalidAgentResponse | 500 | The agent's handler returned
    something malformed |

    | `-32007` | AuthenticatedExtendedCardNotConfigured | 400 | Asked for an
    extended card the agent didn't publish |


    ### Bindu-specific


    | Code | Name | HTTP | When you'll see it |

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

    | `-32008` | TaskImmutable | 400 | Tried to modify a terminal task |

    | `-32009` | AuthenticationRequired | 401 | No bearer token on a protected
    method |

    | `-32010` | InvalidToken | 401 | Token introspection returned `active:
    false` |

    | `-32011` | TokenExpired | 401 | Token's `exp` is in the past |

    | `-32012` | InvalidTokenSignature | 403 | `X-DID-Signature` didn't verify |

    | `-32013` | InsufficientPermissions | 403 | Token is valid, but the scope
    doesn't cover this method |

    | `-32020` | ContextNotFound | 404 | `contextId` doesn't exist |

    | `-32021` | ContextNotCancelable | 400 | Tried to clear a context that
    still has running tasks |

    | `-32030` | SkillNotFound | 404 | `skillId` in the URL doesn't exist |


    ---


    ## Versioning


    A few promises about how this spec changes over time:


    - The path shape is stable. New methods may land under `POST /`,
      but existing methods won't break.
    - Schema fields may get added (backward-compatible). Renames and
      removals always go through a deprecation window, announced in
      the [changelog](https://docs.getbindu.com/changelog).
    - Error code numbers are permanent once assigned. Don't worry
      about `-32009` meaning something different next quarter.
  contact:
    name: Bindu
    url: https://docs.getbindu.com
    email: support@getbindu.com
  license:
    name: Apache-2.0
    url: https://www.apache.org/licenses/LICENSE-2.0.html
servers:
  - url: http://localhost:3773
    description: Local development server
  - url: https://api.getbindu.com
    description: Production Bindu API
security:
  - bearerAuth: []
  - didSignature: []
tags:
  - name: JSON-RPC
    description: |
      The central endpoint (`POST /`). Every task, message, and context
      operation goes here, differentiated by the `method` field inside
      the body.
    externalDocs:
      url: https://docs.getbindu.com/bindu/reference/json-rpc-methods
      description: Method reference with request/response shapes
  - name: Agent Discovery
    description: |
      How clients learn what an agent can do. The agent card
      (`/.well-known/agent.json`) is the canonical A2A discovery
      surface. Skills endpoints expose per-capability metadata.
  - name: DID Resolution
    description: |
      Turn a `did:bindu:...` identifier into a DID Document (the
      public key + verification method + controller). Used by peers
      that want to verify signatures without hitting Hydra directly.
  - name: Skills
    description: |
      Each agent has zero or more `Skill`s. A skill is one specific
      thing the agent can do — with structured input/output types,
      description, and documentation.
  - name: Negotiation
    description: |
      Capability-matching endpoint for orchestrators. Given a task
      summary and constraints, the agent scores whether it can
      handle the task and returns a confidence.
  - name: Payment (x402)
    description: |
      For paid agents. Implements the x402 payment protocol over
      USDC on Base. Session-based so clients don't have to sign
      every request.
  - name: Health & Monitoring
    description: |
      Operator-facing endpoints. `/health` returns 503 when the
      agent is degraded (dependency down, scheduler paused);
      `/metrics` exposes Prometheus text.
paths:
  /health:
    get:
      tags:
        - Health & Monitoring
      summary: Liveness + readiness probe
      description: |
        Returns 200 when healthy, 503 when any mandatory dependency
        (storage, scheduler, message bus, grpc) is degraded. The body
        carries per-component status so orchestrators can show which
        specific thing is broken.
      operationId: getHealth
      responses:
        '200':
          description: Healthy
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HealthResponse'
              example:
                version: 2026.12.6.dev224+gbf39a0530
                health: healthy
                runtime:
                  storage_backend: InMemoryStorage
                  scheduler_backend: InMemoryScheduler
                  task_manager_running: true
                  strict_ready: true
                application:
                  penguin_id: 8faa865e-d8ec-8b2f-f000-598e8e463d60
                  agent_did: >-
                    did:bindu:bindu_builder_at_getbindu_com:agent:8faa865e-d8ec-8b2f-f000-598e8e463d60
                system:
                  python_version: 3.12.9
                  platform: Windows
                  environment: development
                status: ok
                ready: true
                uptime_seconds: 541
        '503':
          description: Degraded — at least one critical component failing
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HealthResponse'
              example:
                status: degraded
                checks:
                  storage: 'error: connection refused'
                  scheduler: ok
                  bus: ok
                  grpc: ok
                  extensions: ok
                timestamp: '2026-04-19T18:00:00+00:00'
      security: []
components:
  schemas:
    HealthResponse:
      type: object
      required:
        - version
        - health
        - runtime
        - application
        - system
        - status
        - ready
        - uptime_seconds
      properties:
        version:
          type: string
          description: Application version with build information
        health:
          type: string
          enum:
            - healthy
            - degraded
          description: Overall health status
        runtime:
          type: object
          properties:
            storage_backend:
              type: string
              description: Storage backend implementation
            scheduler_backend:
              type: string
              description: Scheduler backend implementation
            task_manager_running:
              type: boolean
              description: Whether the task manager is running
            strict_ready:
              type: boolean
              description: Strict readiness mode
        application:
          type: object
          properties:
            penguin_id:
              type: string
              format: uuid
              description: Unique Penguin instance identifier
            agent_did:
              type: string
              description: DID of the agent
        system:
          type: object
          properties:
            python_version:
              type: string
              description: Python runtime version
            platform:
              type: string
              description: Operating system platform
            environment:
              type: string
              description: Runtime environment (development/production)
        status:
          type: string
          enum:
            - ok
            - error
          description: Detailed status
        ready:
          type: boolean
          description: Whether the service is ready to accept requests
        uptime_seconds:
          type: number
          format: float
          description: Service uptime in seconds
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: >
        OAuth2 access token issued by Ory Hydra. Required for most operations.


        **Scopes:**

        - `agent:read` — Read-only operations (tasks/get, tasks/list,
        contexts/list)

        - `agent:write` — Write operations (message/send, tasks/cancel,
        contexts/clear)

        - `agent:execute` — (legacy) Both read and write access


        **How to obtain:**

        1. Register your client with Hydra

        2. Complete OAuth2 client credentials or authorization code flow

        3. Include token in `Authorization: Bearer <token>` header
    didSignature:
      type: apiKey
      in: header
      name: X-DID-Signature
      description: >
        DID-based request signing for agent-to-agent communication.


        **Required headers:**

        - `X-DID`: Your full DID string (e.g., `did:bindu:author:agent:id`)

        - `X-DID-Timestamp`: Unix timestamp in seconds (must be within ±300s)

        - `X-DID-Signature`: Base58-encoded Ed25519 signature


        **Signature payload:**

        ```json

        {"body": <request-body>, "did": "<your-did>", "timestamp":
        <unix-seconds>}

        ```


        The payload is serialized with Python's `json.dumps(...,
        sort_keys=True)` with

        default separators (spaces after `:` and `,`). The signature is verified
        against

        the public key stored in Hydra metadata for your DID.

````