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

# Resolve a DID (via JSON body)

> Alternate form for clients that prefer POST (keeps the DID
out of URL logs). Returns the same document `GET` would.




## OpenAPI

````yaml /openapi.yaml post /did/resolve
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:
  /did/resolve:
    post:
      tags:
        - DID Resolution
      summary: Resolve a DID (via JSON body)
      description: |
        Alternate form for clients that prefer POST (keeps the DID
        out of URL logs). Returns the same document `GET` would.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                did:
                  type: string
                  pattern: ^did:bindu:.+
              required:
                - did
            example:
              did: >-
                did:bindu:example_at_getbindu_com:example-agent:a1b2c3d4-e5f6-7890-abcd-1234567890ab
      responses:
        '200':
          description: DID Document
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DidDocument'
              example:
                '@context':
                  - https://www.w3.org/ns/did/v1
                  - https://getbindu.com/ns/v1
                id: >-
                  did:bindu:bindu_builder_at_getbindu_com:agent:8faa865e-d8ec-8b2f-f000-598e8e463d60
                created: '2026-04-23T09:32:55.168183+00:00'
                authentication:
                  - id: >-
                      did:bindu:bindu_builder_at_getbindu_com:agent:8faa865e-d8ec-8b2f-f000-598e8e463d60#key-1
                    type: Ed25519VerificationKey2020
                    controller: >-
                      did:bindu:bindu_builder_at_getbindu_com:medical_agent:8faa865e-d8ec-8b2f-f000-598e8e463d60
                    publicKeyBase58: G53goNNEDqaHLMJWzdHvnEBG7xDd7jJjjhB3FUwtzWnn
        '400':
          description: Missing or malformed `did` field
        '404':
          description: DID not found
      security: []
components:
  schemas:
    DidDocument:
      type: object
      required:
        - id
        - authentication
      properties:
        '@context':
          type: array
          items:
            type: string
          example:
            - https://www.w3.org/ns/did/v1
            - https://getbindu.com/ns/v1
        id:
          type: string
          pattern: ^did:bindu:.+
        created:
          type: string
          format: date-time
        authentication:
          type: array
          items:
            $ref: '#/components/schemas/VerificationMethod'
        verificationMethod:
          type: array
          items:
            $ref: '#/components/schemas/VerificationMethod'
    VerificationMethod:
      type: object
      required:
        - id
        - type
        - controller
        - publicKeyBase58
      properties:
        id:
          type: string
          description: DID-URL, typically `<did>#key-1`.
        type:
          type: string
          enum:
            - Ed25519VerificationKey2020
        controller:
          type: string
          description: DID of the entity that controls this key.
        publicKeyBase58:
          type: string
          description: Base58-encoded 32-byte Ed25519 public key.
  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.

````