> ## 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.

# JSON-RPC 2.0 endpoint (all agent operations dispatch here)

> Every write or read operation on tasks, messages, and contexts
uses this endpoint. The `method` field in the body selects the
operation. See the *Error catalog* in the top-level description
for every possible `error.code`.

**Accepted methods:** `message/send`, `message/stream`
*(experimental)*, `tasks/get`, `tasks/list`, `tasks/cancel`,
`tasks/feedback`, `contexts/list`, `contexts/clear`.

**Casing tolerance:** the server accepts both camelCase
(`taskId`) and snake_case (`task_id`) in `params` — pick one
and stick with it per-call. Responses are always snake_case.

**Size limit:** request bodies over 10 MB return `413
Payload Too Large` at the ASGI layer (does not use the
JSON-RPC error envelope).

**Idempotency:** `message/send` is NOT idempotent — a repeat
call creates a new task. If you need idempotency, have your
client generate a stable `messageId` and use `contexts/list`
+ `tasks/list` to check whether you've already sent it.




## OpenAPI

````yaml /openapi.yaml post /
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:
  /:
    post:
      tags:
        - JSON-RPC
      summary: JSON-RPC 2.0 endpoint (all agent operations dispatch here)
      description: |
        Every write or read operation on tasks, messages, and contexts
        uses this endpoint. The `method` field in the body selects the
        operation. See the *Error catalog* in the top-level description
        for every possible `error.code`.

        **Accepted methods:** `message/send`, `message/stream`
        *(experimental)*, `tasks/get`, `tasks/list`, `tasks/cancel`,
        `tasks/feedback`, `contexts/list`, `contexts/clear`.

        **Casing tolerance:** the server accepts both camelCase
        (`taskId`) and snake_case (`task_id`) in `params` — pick one
        and stick with it per-call. Responses are always snake_case.

        **Size limit:** request bodies over 10 MB return `413
        Payload Too Large` at the ASGI layer (does not use the
        JSON-RPC error envelope).

        **Idempotency:** `message/send` is NOT idempotent — a repeat
        call creates a new task. If you need idempotency, have your
        client generate a stable `messageId` and use `contexts/list`
        + `tasks/list` to check whether you've already sent it.
      operationId: jsonRpcEndpoint
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/JsonRpcRequest'
            examples:
              messageSend:
                summary: Kick off a task (simplest form)
                value:
                  jsonrpc: '2.0'
                  method: message/send
                  id: 550e8400-e29b-41d4-a716-446655440001
                  params:
                    message:
                      role: user
                      parts:
                        - kind: text
                          text: What is the capital of France?
                      kind: message
                      message_id: 550e8400-e29b-41d4-a716-446655440002
                      contextId: 550e8400-e29b-41d4-a716-446655440003
                      taskId: 550e8400-e29b-41d4-a716-446655440004
                    configuration:
                      acceptedOutputModes:
                        - application/json
                        - text/plain
                        - text/markdown
              messageSendChained:
                summary: Continue from an earlier task (Task A → Task B)
                description: |
                  Pass `referenceTaskIds` to make this task depend on
                  a previous one. The server propagates the earlier
                  task's artifacts into this task's context.
                value:
                  jsonrpc: '2.0'
                  method: message/send
                  id: 550e8400-e29b-41d4-a716-446655440005
                  params:
                    message:
                      role: user
                      parts:
                        - kind: text
                          text: Summarize the previous analysis in three bullets.
                      kind: message
                      message_id: 550e8400-e29b-41d4-a716-446655440006
                      contextId: 550e8400-e29b-41d4-a716-446655440003
                      taskId: 550e8400-e29b-41d4-a716-446655440007
                      referenceTaskIds:
                        - 550e8400-e29b-41d4-a716-446655440004
                    configuration:
                      acceptedOutputModes:
                        - application/json
              messageSendWithPayment:
                summary: Paid agent (x402 payload inline in metadata)
                description: |
                  When the agent requires payment and you've already
                  executed the x402 flow, embed the payload in
                  `message.metadata.x402.payment` with
                  `status: "payment-submitted"`. The server's
                  middleware auto-injects the verified context into
                  `message.metadata._payment_context` before the
                  handler sees the message — don't set
                  `_payment_context` yourself.
                value:
                  jsonrpc: '2.0'
                  method: message/send
                  id: 550e8400-e29b-41d4-a716-446655440008
                  params:
                    message:
                      role: user
                      parts:
                        - kind: text
                          text: Run the full premium analysis.
                      kind: message
                      message_id: 550e8400-e29b-41d4-a716-446655440009
                      contextId: 550e8400-e29b-41d4-a716-446655440003
                      taskId: 550e8400-e29b-41d4-a716-446655440010
                      metadata:
                        x402:
                          payment:
                            status: payment-submitted
                            payload:
                              resource: https://agent.example.com/premium
                              scheme: exact
                              network: base-sepolia
                              asset: '0x036CbD53842c5426634e7929541eC2318f3dCF7e'
                              payTo: '0x2654bb8B272f117c514aAc3d4032B1795366BA5d'
                              amount: '100'
                              signature: >-
                                0x860d5fc4507efdfaef30b37c475c1fcd609aed8b5f0624f7e3e1ec56b0a2cd2e
                              timestamp: 1776607158
                              payer: '0x5eE83F6DfF98F3DAf1B8a43DBd4B837e7E04e4Dc'
                    configuration:
                      acceptedOutputModes:
                        - application/json
              tasksGet:
                summary: Poll a task by id
                value:
                  jsonrpc: '2.0'
                  method: tasks/get
                  id: 550e8400-e29b-41d4-a716-446655440011
                  params:
                    taskId: 550e8400-e29b-41d4-a716-446655440004
              tasksGetWithHistory:
                summary: Poll and trim history to the last N turns
                description: |
                  `historyLength` caps the returned `history` array
                  to the most recent N messages. Useful for polling
                  loops where you only want the newest updates.
                value:
                  jsonrpc: '2.0'
                  method: tasks/get
                  id: 550e8400-e29b-41d4-a716-446655440012
                  params:
                    taskId: 550e8400-e29b-41d4-a716-446655440004
                    historyLength: 5
              tasksList:
                summary: List the caller's recent tasks
                description: |
                  Returns tasks scoped to the caller's DID (when
                  auth is on). `history_length` caps the `history`
                  array inside each returned task — it does NOT
                  cap the number of tasks returned.
                value:
                  jsonrpc: '2.0'
                  method: tasks/list
                  id: 550e8400-e29b-41d4-a716-446655440013
                  params:
                    history_length: 10
              tasksCancel:
                summary: Cancel a running task
                value:
                  jsonrpc: '2.0'
                  method: tasks/cancel
                  id: 550e8400-e29b-41d4-a716-446655440014
                  params:
                    taskId: 550e8400-e29b-41d4-a716-446655440004
              tasksFeedback:
                summary: Rate a completed task
                description: |
                  Feedback is advisory — stored against the task row
                  for later analytics. Does NOT modify the task's
                  state (it's already terminal).
                value:
                  jsonrpc: '2.0'
                  method: tasks/feedback
                  id: 550e8400-e29b-41d4-a716-446655440015
                  params:
                    taskId: 550e8400-e29b-41d4-a716-446655440004
                    feedback: Answer was accurate but slow.
                    rating: 4
                    metadata:
                      category: quality
                      helpful: true
              contextsList:
                summary: List active contexts
                description: |
                  `history_length` caps tasks-per-context in the
                  returned view. Does not cap number of contexts.
                value:
                  jsonrpc: '2.0'
                  method: contexts/list
                  id: 550e8400-e29b-41d4-a716-446655440016
                  params:
                    history_length: 10
              contextsClear:
                summary: Clear a context (all non-running tasks purged)
                description: |
                  Running tasks inside the context are NOT affected.
                  The agent may refuse with `-32021 ContextNotCancelable`
                  if any task is still `working`.
                value:
                  jsonrpc: '2.0'
                  method: contexts/clear
                  id: 550e8400-e29b-41d4-a716-446655440017
                  params:
                    contextId: 550e8400-e29b-41d4-a716-446655440003
              tasksPushNotificationSet:
                summary: Register a webhook on an existing task
                description: |
                  Inline registration via `message/send` is also
                  supported, but this RPC lets you attach (or update)
                  a webhook after the task was created.
                value:
                  jsonrpc: '2.0'
                  method: tasks/pushNotificationConfig/set
                  id: 550e8400-e29b-41d4-a716-446655440018
                  params:
                    id: 550e8400-e29b-41d4-a716-446655440004
                    long_running: true
                    push_notification_config:
                      id: 550e8400-e29b-41d4-a716-446655440019
                      url: https://myapp.example.com/webhooks/task-updates
                      token: secret_abc123
              tasksPushNotificationGet:
                summary: Fetch the webhook registered for a task
                value:
                  jsonrpc: '2.0'
                  method: tasks/pushNotificationConfig/get
                  id: 550e8400-e29b-41d4-a716-446655440020
                  params:
                    task_id: 550e8400-e29b-41d4-a716-446655440004
              tasksPushNotificationList:
                summary: List webhook configs for a task
                value:
                  jsonrpc: '2.0'
                  method: tasks/pushNotificationConfig/list
                  id: 550e8400-e29b-41d4-a716-446655440021
                  params:
                    id: 550e8400-e29b-41d4-a716-446655440004
              tasksPushNotificationDelete:
                summary: Remove a specific webhook from a task
                value:
                  jsonrpc: '2.0'
                  method: tasks/pushNotificationConfig/delete
                  id: 550e8400-e29b-41d4-a716-446655440022
                  params:
                    id: 550e8400-e29b-41d4-a716-446655440004
                    push_notification_config_id: 550e8400-e29b-41d4-a716-446655440019
      responses:
        '200':
          description: |
            Successful JSON-RPC response. `result` contains the typed
            output per method — see `components/schemas/*Result`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonRpcResponse'
              examples:
                messageSendSubmitted:
                  summary: 'message/send → state: submitted'
                  description: Task created and queued. Poll `tasks/get` for progress.
                  value:
                    jsonrpc: '2.0'
                    id: 550e8400-e29b-41d4-a716-446655440001
                    result:
                      id: 550e8400-e29b-41d4-a716-446655440004
                      context_id: 550e8400-e29b-41d4-a716-446655440003
                      kind: task
                      status:
                        state: submitted
                        timestamp: '2026-04-19T18:30:00.000000+00:00'
                      history:
                        - kind: message
                          role: user
                          parts:
                            - kind: text
                              text: What is the capital of France?
                          task_id: 550e8400-e29b-41d4-a716-446655440004
                          context_id: 550e8400-e29b-41d4-a716-446655440003
                          message_id: 550e8400-e29b-41d4-a716-446655440002
                      artifacts: []
                      metadata: {}
                tasksGetWorking:
                  summary: 'tasks/get → state: working'
                  value:
                    jsonrpc: '2.0'
                    id: 550e8400-e29b-41d4-a716-446655440011
                    result:
                      id: 550e8400-e29b-41d4-a716-446655440004
                      context_id: 550e8400-e29b-41d4-a716-446655440003
                      kind: task
                      status:
                        state: working
                        timestamp: '2026-04-19T18:30:15.000000+00:00'
                      history: []
                      artifacts: []
                      metadata: {}
                tasksGetInputRequired:
                  summary: 'tasks/get → state: input-required (paused)'
                  description: |
                    The agent paused and needs clarification. Look at
                    `status.message` for the question; send a new
                    `message/send` on the same context to continue.
                  value:
                    jsonrpc: '2.0'
                    id: 550e8400-e29b-41d4-a716-446655440011
                    result:
                      id: 550e8400-e29b-41d4-a716-446655440004
                      context_id: 550e8400-e29b-41d4-a716-446655440003
                      kind: task
                      status:
                        state: input-required
                        timestamp: '2026-04-19T18:30:30.000000+00:00'
                        message:
                          role: agent
                          parts:
                            - kind: text
                              text: >-
                                Which period should I analyze — last 30 days or
                                year-to-date?
                      history: []
                      artifacts: []
                      metadata: {}
                tasksGetCompleted:
                  summary: 'tasks/get → state: completed'
                  description: |
                    Work finished. The answer is in `artifacts[]`.
                    `metadata.did.message.signature` (when present)
                    is the agent's Ed25519 signature over the artifact
                    text — clients can verify authenticity via DID
                    resolution.
                  value:
                    jsonrpc: '2.0'
                    id: 550e8400-e29b-41d4-a716-446655440011
                    result:
                      id: 550e8400-e29b-41d4-a716-446655440004
                      context_id: 550e8400-e29b-41d4-a716-446655440003
                      kind: task
                      status:
                        state: completed
                        timestamp: '2026-04-19T18:31:00.000000+00:00'
                      history:
                        - kind: message
                          role: user
                          parts:
                            - kind: text
                              text: What is the capital of France?
                          task_id: 550e8400-e29b-41d4-a716-446655440004
                          context_id: 550e8400-e29b-41d4-a716-446655440003
                          message_id: 550e8400-e29b-41d4-a716-446655440002
                        - kind: message
                          role: assistant
                          parts:
                            - kind: text
                              text: Paris.
                          task_id: 550e8400-e29b-41d4-a716-446655440004
                          context_id: 550e8400-e29b-41d4-a716-446655440003
                          message_id: 589ef550-fefa-4d3a-a5ed-ee9936a20992
                      artifacts:
                        - name: result
                          parts:
                            - kind: text
                              text: Paris.
                              metadata:
                                did.message.signature: >-
                                  2M1qbfLcyoQhSAfTzDghw15PMTfmv3jUoigk7KRuiowkEWZpU7aYLHTnqwamjEo4SxNskq15PZANNLuhJ7omzsxg
                          artifact_id: 985b4f37-ee2e-48a4-bd6f-c66472e67b85
                      metadata: {}
                tasksGetFailed:
                  summary: 'tasks/get → state: failed'
                  description: |
                    Processing error. `status.message` carries the
                    human-readable cause. Task is terminal — can't
                    be resumed; submit a fresh message if you want
                    to retry.
                  value:
                    jsonrpc: '2.0'
                    id: 550e8400-e29b-41d4-a716-446655440011
                    result:
                      id: 550e8400-e29b-41d4-a716-446655440004
                      context_id: 550e8400-e29b-41d4-a716-446655440003
                      kind: task
                      status:
                        state: failed
                        timestamp: '2026-04-19T18:30:45.000000+00:00'
                        message:
                          role: agent
                          parts:
                            - kind: text
                              text: Upstream data source unavailable; tried 3 times.
                      history: []
                      artifacts: []
                      metadata: {}
                tasksGetRejected:
                  summary: 'tasks/get → state: rejected'
                  description: |
                    Agent declined to process the input (e.g., outside
                    its capability scope, invalid format). Check
                    `status.message` for the decline reason.
                  value:
                    jsonrpc: '2.0'
                    id: 550e8400-e29b-41d4-a716-446655440011
                    result:
                      id: 550e8400-e29b-41d4-a716-446655440004
                      context_id: 550e8400-e29b-41d4-a716-446655440003
                      kind: task
                      status:
                        state: rejected
                        timestamp: '2026-04-19T18:30:01.000000+00:00'
                        message:
                          role: agent
                          parts:
                            - kind: text
                              text: >-
                                Request is outside this agent's declared
                                capabilities.
                      history: []
                      artifacts: []
                      metadata: {}
                tasksListResult:
                  summary: tasks/list result
                  value:
                    jsonrpc: '2.0'
                    id: 550e8400-e29b-41d4-a716-446655440013
                    result:
                      - id: 550e8400-e29b-41d4-a716-446655440004
                        context_id: 550e8400-e29b-41d4-a716-446655440003
                        kind: task
                        status:
                          state: completed
                          timestamp: '2026-04-19T18:31:00.000000+00:00'
                        history: []
                        artifacts: []
                        metadata: {}
                tasksCancelResult:
                  summary: tasks/cancel result (state flips to 'canceled')
                  value:
                    jsonrpc: '2.0'
                    id: 550e8400-e29b-41d4-a716-446655440014
                    result:
                      id: 550e8400-e29b-41d4-a716-446655440004
                      context_id: 550e8400-e29b-41d4-a716-446655440003
                      kind: task
                      status:
                        state: canceled
                        timestamp: '2026-04-19T18:30:50.000000+00:00'
                      history: []
                      artifacts: []
                      metadata: {}
                tasksFeedbackResult:
                  summary: tasks/feedback result
                  value:
                    jsonrpc: '2.0'
                    id: 550e8400-e29b-41d4-a716-446655440015
                    result:
                      success: true
                contextsListResult:
                  summary: contexts/list result
                  value:
                    jsonrpc: '2.0'
                    id: 550e8400-e29b-41d4-a716-446655440016
                    result:
                      - context_id: 550e8400-e29b-41d4-a716-446655440003
                        kind: context
                        role: user
                        tasks:
                          - 550e8400-e29b-41d4-a716-446655440004
                        status: active
                        created_at: '2026-04-19T18:29:00.000000+00:00'
                        updated_at: '2026-04-19T18:31:00.000000+00:00'
                        name: France capitals inquiry
                        metadata: {}
                contextsClearResult:
                  summary: contexts/clear result
                  value:
                    jsonrpc: '2.0'
                    id: 550e8400-e29b-41d4-a716-446655440017
                    result:
                      success: true
                errorTaskNotFound:
                  summary: Error — TaskNotFound (-32001)
                  value:
                    jsonrpc: '2.0'
                    id: 550e8400-e29b-41d4-a716-446655440011
                    error:
                      code: -32001
                      message: Task not found
                      data:
                        taskId: 550e8400-e29b-41d4-a716-446655440099
                errorTaskNotCancelable:
                  summary: Error — TaskNotCancelable (-32002)
                  description: Cannot cancel a task that's already terminal.
                  value:
                    jsonrpc: '2.0'
                    id: 550e8400-e29b-41d4-a716-446655440014
                    error:
                      code: -32002
                      message: >-
                        Task is already in terminal state 'completed' and cannot
                        be canceled
                errorInvalidParams:
                  summary: Error — Invalid params (-32602)
                  description: params didn't match the method's schema
                  value:
                    jsonrpc: '2.0'
                    id: 550e8400-e29b-41d4-a716-446655440001
                    error:
                      code: -32602
                      message: 'Invalid params: missing ''message.parts'''
                errorAuthRequired:
                  summary: Error — AuthenticationRequired (-32009)
                  value:
                    jsonrpc: '2.0'
                    id: 550e8400-e29b-41d4-a716-446655440001
                    error:
                      code: -32009
                      message: Authentication required for method 'message/send'
                errorInsufficientPermissions:
                  summary: Error — InsufficientPermissions (-32013)
                  description: Valid token but scope doesn't cover the method.
                  value:
                    jsonrpc: '2.0'
                    id: 550e8400-e29b-41d4-a716-446655440001
                    error:
                      code: -32013
                      message: >-
                        Scope 'agent:read' does not permit method
                        'message/send'; requires 'agent:write'
                errorInvalidSignature:
                  summary: Error — InvalidTokenSignature (-32012)
                  description: X-DID-Signature failed Ed25519 verification.
                  value:
                    jsonrpc: '2.0'
                    id: 550e8400-e29b-41d4-a716-446655440001
                    error:
                      code: -32012
                      message: Invalid DID signature
                      data:
                        reason: crypto_mismatch
        '400':
          description: Invalid JSON-RPC request (malformed body)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonRpcResponse'
              example:
                jsonrpc: '2.0'
                id: null
                error:
                  code: -32700
                  message: Parse error
        '401':
          description: Missing or invalid bearer token
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
              example:
                error: Unauthorized
        '403':
          description: Token valid but DID signature failed (when DID signing is required)
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                  details:
                    type: object
                    properties:
                      did_verified:
                        type: boolean
                      reason:
                        type: string
                        enum:
                          - missing_signature_headers
                          - did_mismatch
                          - public_key_unavailable
                          - timestamp_out_of_window
                          - crypto_mismatch
                          - malformed_input
              example:
                error: Invalid DID signature
                details:
                  did_verified: false
                  reason: did_mismatch
        '413':
          description: Request body exceeded the 10 MB limit
        '500':
          description: Internal error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonRpcResponse'
              example:
                jsonrpc: '2.0'
                id: 550e8400-e29b-41d4-a716-446655440001
                error:
                  code: -32603
                  message: Internal error
      security:
        - bearerAuth: []
        - bearerAuth: []
          didSignature: []
components:
  schemas:
    JsonRpcRequest:
      description: |
        JSON-RPC 2.0 request envelope. One of the per-method
        `params` shapes must be supplied via the `method` field.
      type: object
      required:
        - jsonrpc
        - method
        - id
      properties:
        jsonrpc:
          type: string
          const: '2.0'
        method:
          type: string
          enum:
            - message/send
            - message/stream
            - tasks/get
            - tasks/list
            - tasks/cancel
            - tasks/feedback
            - tasks/pushNotificationConfig/set
            - tasks/pushNotificationConfig/get
            - tasks/pushNotificationConfig/list
            - tasks/pushNotificationConfig/delete
            - contexts/list
            - contexts/clear
        id:
          oneOf:
            - type: string
            - type: integer
          description: Caller-chosen request id. The response echoes it back.
        params:
          description: Method-specific params (see per-method schemas below)
          oneOf:
            - $ref: '#/components/schemas/MessageSendParams'
            - $ref: '#/components/schemas/TasksGetParams'
            - $ref: '#/components/schemas/TasksListParams'
            - $ref: '#/components/schemas/TasksCancelParams'
            - $ref: '#/components/schemas/TasksFeedbackParams'
            - $ref: '#/components/schemas/SetTaskPushNotificationConfigParams'
            - $ref: '#/components/schemas/GetTaskPushNotificationConfigParams'
            - $ref: '#/components/schemas/ListTaskPushNotificationConfigParams'
            - $ref: '#/components/schemas/DeleteTaskPushNotificationConfigParams'
            - $ref: '#/components/schemas/ContextsListParams'
            - $ref: '#/components/schemas/ContextsClearParams'
    JsonRpcResponse:
      description: |
        JSON-RPC 2.0 response envelope. Exactly one of `result` or
        `error` is present.
      type: object
      required:
        - jsonrpc
        - id
      properties:
        jsonrpc:
          type: string
          const: '2.0'
        id:
          oneOf:
            - type: string
            - type: integer
            - type: 'null'
        result:
          description: Method-specific result (see per-method result schemas)
          oneOf:
            - $ref: '#/components/schemas/Task'
            - type: array
              items:
                $ref: '#/components/schemas/Task'
            - type: array
              items:
                $ref: '#/components/schemas/Context'
            - $ref: '#/components/schemas/TasksFeedbackResult'
            - $ref: '#/components/schemas/ContextsClearResult'
        error:
          $ref: '#/components/schemas/JsonRpcError'
    MessageSendParams:
      type: object
      required:
        - message
      properties:
        message:
          $ref: '#/components/schemas/UserMessage'
        configuration:
          $ref: '#/components/schemas/MessageSendConfiguration'
        metadata:
          type: object
          additionalProperties: true
    TasksGetParams:
      type: object
      required:
        - taskId
      properties:
        taskId:
          type: string
          format: uuid
        historyLength:
          type: integer
          minimum: 0
          description: Cap `history` array in the returned task.
        metadata:
          type: object
          additionalProperties: true
    TasksListParams:
      type: object
      description: |
        Use `history_length` (snake_case) to cap the `history`
        array inside each returned task. The server returns all
        tasks scoped to the caller's DID (or the whole agent's
        tasks when auth is off) — there is no cursor-based
        pagination yet.
      properties:
        history_length:
          type: integer
          minimum: 0
          description: Cap `history` array per returned task.
        metadata:
          type: object
          additionalProperties: true
    TasksCancelParams:
      type: object
      required:
        - taskId
      properties:
        taskId:
          type: string
          format: uuid
    TasksFeedbackParams:
      type: object
      required:
        - taskId
        - feedback
      properties:
        taskId:
          type: string
          format: uuid
        feedback:
          type: string
          description: Human-readable feedback text.
        rating:
          type: integer
          minimum: 1
          maximum: 5
          description: 1 (worst) – 5 (best).
        metadata:
          type: object
          additionalProperties: true
    SetTaskPushNotificationConfigParams:
      type: object
      required:
        - id
        - push_notification_config
      description: Register a webhook for task updates.
      properties:
        id:
          type: string
          format: uuid
          description: Task id to attach the webhook to.
        push_notification_config:
          $ref: '#/components/schemas/PushNotificationConfig'
        long_running:
          type: boolean
          default: false
          description: |
            When `true`, the webhook is persisted to the database and
            restored if the server restarts.
    GetTaskPushNotificationConfigParams:
      type: object
      required:
        - task_id
      description: Fetch the webhook currently registered for a task.
      properties:
        task_id:
          type: string
          format: uuid
    ListTaskPushNotificationConfigParams:
      type: object
      required:
        - id
      description: List webhook configs for a task.
      properties:
        id:
          type: string
          format: uuid
          description: Task id.
        metadata:
          type: object
          additionalProperties: true
    DeleteTaskPushNotificationConfigParams:
      type: object
      required:
        - id
        - push_notification_config_id
      description: Remove a specific webhook from a task.
      properties:
        id:
          type: string
          format: uuid
          description: Task id.
        push_notification_config_id:
          type: string
          format: uuid
          description: Webhook id to remove.
    ContextsListParams:
      type: object
      description: |
        Use `history_length` (snake_case) to cap the tasks-per-context
        in the returned view. It does not cap the number of contexts
        returned.
      properties:
        history_length:
          type: integer
          minimum: 0
        metadata:
          type: object
          additionalProperties: true
    ContextsClearParams:
      type: object
      required:
        - contextId
      properties:
        contextId:
          type: string
          format: uuid
    Task:
      type: object
      required:
        - id
        - context_id
        - kind
        - status
      properties:
        id:
          type: string
          format: uuid
        context_id:
          type: string
          format: uuid
        kind:
          type: string
          const: task
        status:
          $ref: '#/components/schemas/TaskStatus'
        history:
          type: array
          description: Conversation history for this task
          items:
            $ref: '#/components/schemas/HistoryMessage'
        artifacts:
          type: array
          description: |
            Work product. Populated as work proceeds; final result
            is here when state = `completed`.
          items:
            $ref: '#/components/schemas/Artifact'
        metadata:
          type: object
          additionalProperties: true
    Context:
      type: object
      required:
        - context_id
        - kind
        - role
        - created_at
        - updated_at
      properties:
        context_id:
          type: string
          format: uuid
        kind:
          type: string
          const: context
        role:
          type: string
          description: |
            Conversation participant role. Typically `"user"`. Some
            agents use `"system"` for system-managed contexts.
        name:
          type: string
          description: Short label for UIs.
        description:
          type: string
        tasks:
          type: array
          items:
            type: string
            format: uuid
          description: IDs of every task in this context.
        status:
          type: string
          enum:
            - active
            - paused
            - completed
            - archived
        tags:
          type: array
          items:
            type: string
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        parent_context_id:
          type: string
          format: uuid
          description: For nested conversations (threads within a thread).
        reference_context_ids:
          type: array
          items:
            type: string
            format: uuid
        extensions:
          type: object
          additionalProperties: true
        metadata:
          type: object
          additionalProperties: true
    TasksFeedbackResult:
      type: object
      required:
        - success
      properties:
        success:
          type: boolean
    ContextsClearResult:
      type: object
      required:
        - success
      properties:
        success:
          type: boolean
    JsonRpcError:
      type: object
      required:
        - code
        - message
      properties:
        code:
          type: integer
          description: |
            Error code. See the *Error catalog* in the top-level
            description for the full list.
        message:
          type: string
        data:
          description: Optional structured detail — varies per error.
          type: object
          additionalProperties: true
    UserMessage:
      type: object
      required:
        - role
        - parts
        - kind
        - message_id
      properties:
        role:
          type: string
          enum:
            - user
        parts:
          type: array
          minItems: 1
          items:
            $ref: '#/components/schemas/MessagePart'
        kind:
          type: string
          const: message
        message_id:
          type: string
          format: uuid
        contextId:
          type: string
          format: uuid
          description: |
            Conversation context. New contexts are created
            automatically when omitted; pass a previous
            `contextId` to continue the same conversation.
        taskId:
          type: string
          format: uuid
          description: |
            Caller-provided task id. The server uses this as the
            outbound task's id — lets clients correlate before a
            response arrives.
        referenceTaskIds:
          type: array
          items:
            type: string
            format: uuid
          description: |
            Earlier tasks this task depends on. The server fetches
            their artifacts and makes them available to the handler
            as context.
        metadata:
          type: object
          additionalProperties: true
          description: |
            Free-form. Two reserved keys:
            - `x402.payment` — inline x402 payment submission (see
              the `message/send - With Payment` example).
            - `_payment_context` — server-injected, read-only; the
              verified x402 context. Do not set this yourself.
    MessageSendConfiguration:
      type: object
      required:
        - acceptedOutputModes
      properties:
        acceptedOutputModes:
          type: array
          minItems: 1
          items:
            type: string
          description: |
            MIME types the client accepts in artifacts. Common
            values: `application/json`, `text/plain`,
            `text/markdown`. If the agent can't produce any of
            these, it returns `-32005 ContentTypeNotSupported`.
          example:
            - application/json
            - text/markdown
        blocking:
          type: boolean
          default: false
          description: |
            If `true`, the server holds the HTTP connection open
            until the task reaches a terminal state. Use sparingly
            — most agents work asynchronously and blocking defeats
            that design. Short tasks (<1s) only.
        historyLength:
          type: integer
          minimum: 0
          description: Cap `history` array in the returned task.
        push_notification_config:
          type: object
          description: >
            Register a webhook to receive task updates (status +

            artifact events) as the task progresses. The agent must

            declare `push_notifications: true` in its capabilities.

            See the [push notifications
            guide](https://docs.getbindu.com/bindu/learn/notification/overview)

            for event payloads.
          properties:
            id:
              type: string
              format: uuid
              description: Unique identifier for this webhook registration.
            url:
              type: string
              format: uri
              description: Your webhook endpoint. The agent POSTs events here.
            token:
              type: string
              description: |
                Shared secret. The agent sends it back as
                `Authorization: Bearer <token>` so you can verify
                the request came from the agent.
        longRunning:
          type: boolean
          default: false
          description: |
            Hint that the task will take >60s. Some agents use this
            to pre-check resources before acknowledging.
    PushNotificationConfig:
      type: object
      required:
        - id
        - url
      description: |
        Webhook configuration for receiving task updates. Register it
        with `tasks/pushNotificationConfig/set` or inline via
        `configuration.push_notification_config` on `message/send`.
      properties:
        id:
          type: string
          format: uuid
          description: Stable identifier for this webhook registration.
        url:
          type: string
          format: uri
          description: HTTPS URL the agent will POST updates to.
        token:
          type: string
          description: |
            Shared secret sent back as `Authorization: Bearer <token>`
            so you can verify the request came from the agent.
        authentication:
          type: object
          additionalProperties: true
          description: Optional advanced auth schemes (reserved).
    TaskStatus:
      type: object
      required:
        - state
        - timestamp
      properties:
        state:
          type: string
          enum:
            - submitted
            - working
            - input-required
            - auth-required
            - completed
            - failed
            - canceled
            - rejected
          description: |
            See the top-level description for the state machine.
            Terminal states (`completed`, `failed`, `canceled`,
            `rejected`) are immutable.
        timestamp:
          type: string
          format: date-time
          description: ISO 8601 with UTC offset, of the last state transition.
        message:
          $ref: '#/components/schemas/HistoryMessage'
          description: |
            Optional status-change annotation. For `input-required`
            / `auth-required`, this is the agent's question. For
            `failed`/`rejected`, the reason.
    HistoryMessage:
      type: object
      required:
        - kind
        - role
        - parts
      properties:
        kind:
          type: string
          const: message
        role:
          type: string
          enum:
            - user
            - assistant
            - agent
        parts:
          type: array
          items:
            $ref: '#/components/schemas/MessagePart'
        task_id:
          type: string
          format: uuid
        context_id:
          type: string
          format: uuid
        message_id:
          type: string
          format: uuid
    Artifact:
      type: object
      required:
        - artifact_id
        - parts
      properties:
        artifact_id:
          type: string
          format: uuid
        name:
          type: string
          description: Short display label, e.g. `"result"`, `"summary"`, `"sources"`.
        description:
          type: string
        parts:
          type: array
          items:
            $ref: '#/components/schemas/MessagePart'
          description: |
            Each part has its own MIME kind. The `metadata` on a
            part may include `did.message.signature` — a base58
            Ed25519 signature the agent made over `parts[i].text`
            (or `data`), verifiable via the agent's DID document.
        metadata:
          type: object
          additionalProperties: true
    MessagePart:
      oneOf:
        - type: object
          required:
            - kind
            - text
          properties:
            kind:
              type: string
              const: text
            text:
              type: string
            metadata:
              type: object
              additionalProperties: true
        - type: object
          required:
            - kind
            - data
          properties:
            kind:
              type: string
              const: data
            data:
              type: object
              additionalProperties: true
            metadata:
              type: object
              additionalProperties: true
        - type: object
          required:
            - kind
            - file
          properties:
            kind:
              type: string
              const: file
            file:
              type: object
              properties:
                mime_type:
                  type: string
                uri:
                  type: string
                  format: uri
                bytes:
                  type: string
                  format: byte
                  description: Base64-encoded inline content
            metadata:
              type: object
              additionalProperties: true
  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.

````