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

# Who this credential is

> The agent, its addresses, its mailbox, calendars and addressbook,
and what it may reach. The first call a client should make.




## OpenAPI

````yaml /api/bud-api.yaml post /v1/me.describe
openapi: 3.0.3
info:
  title: Noetive Bud API
  version: 0.1.0
  description: >
    Noetive Bud is a managed mail, calendar and addressbook service whose

    first-class users are agents. People reach the same data through ordinary

    mail and calendar clients; a program reaches it through this API.


    All request and response bodies are JSON. Every operation is a `POST`,

    including the ones that only read. The input is a document rather than a

    query string, so a caller assembles a typed body instead of encoding

    filters into a URL. `/v1/watch` accepts a JSON `POST` and upgrades the

    response to a Server-Sent Events stream.


    ## Four operations over one grammar


    Underneath the operation names below there are four verbs: **wait**,

    **read**, **put** and **send**, over one uniform way of naming things.

    That is why the surface does not grow an operation every time it grows a

    kind of object. A client that has learned the grammar can reach what was

    added after it was written.


    `POST /v1/help.describe` returns the grammar itself, and

    `POST /v1/catalog.describe` returns what this deployment serves. Both are

    cheap and neither needs anything but a valid credential.


    ## Identity and scope


    Every request carries a bearer token. A token belongs to an agent, an

    agent belongs to one account, and an agent reads and writes its own

    mailbox, calendar and addressbook. A grant may extend that to another

    agent's, never beyond the account.


    There is no operation on this surface that creates an account, an agent or

    a token. Those are administrative and are not reachable with an agent

    credential.


    ## Errors


    A refusal is a JSON object with an `error` member, at the HTTP status the

    code maps to. The status is the part to branch on; the code is the part to

    branch within.


    | code | status | meaning |

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

    | `invalid` | 400 | The request is malformed or a field is wrong. `field` is
    a JSON pointer to it. |

    | `unauthorized` | 401 | The credential is missing, unknown, revoked or
    expired. |

    | `not_billable` | 402 | The credential is good and the account behind it
    cannot incur usage. |

    | `forbidden_scope` | 403 | The credential is valid and does not reach this
    object, or does not reach an agent on this service at all. |

    | `not_found` | 404 | No such object, or no such operation. |

    | `precondition_failed` | 409 | Someone else wrote first, or a version was
    needed and not sent. `version` is the value to retry with. |

    | `policy_refused` | 422 | A policy declined. The message says which. |

    | `rate_limited` | 429 | A limit is spent. `retry_after_ms` says how long to
    wait. |

    | `paused` | 503 | The mailbox is paused and is not sending. |

    | `upstream_unavailable` | 503 | Something this request needed did not
    answer. Retry with backoff. |

    | `unavailable` | 501 | This deployment does not implement the operation. Do
    not retry it. |

    | `internal` | 500 | Something went wrong that is not about the request. |


    Every response, successful or not, carries an `X-Request-Id` header, and a

    refusal repeats it as `error.request_id`. Quote it in a support request: it

    correlates the refusal with everything the request caused.


    `unavailable` is deliberately 501 rather than 500. It means this build

    never serves the operation without a new deployment, and retry policies

    are written against statuses.


    ### Only 401 means the credential is the problem


    Four refusals concern the credential's surroundings rather than the

    credential, and only one of them is worth minting a new key over.


    Treat **401** as "this key never works": stop presenting it. `403`,

    `402` and `upstream_unavailable` all mean the key itself is fine. It

    reaches no agent here, or the account cannot currently incur usage, or

    something the request needed did not answer. A client that reacts to those

    by discarding the key throws away a working credential and gets no further,

    which is why they are separate statuses and why `WWW-Authenticate` is sent

    with the 401 and with nothing else. Branch on the header's presence if that

    is easier than branching on the status.


    `upstream_unavailable` is the one to retry. It is transient by definition,

    and the request had no effect.


    ## Limits


    | limit | value |

    | --- | --- |

    | request body | 1 MiB, or 16 MiB for a blob create carrying its bytes
    inline |

    | JSON nesting depth | 64 |


    A body over the limit is refused as `invalid` with a JSON envelope, not as

    a bare transport error, so one error path covers size and shape alike.


    ## Concurrency


    An operation that changes a stored object takes a `version` and returns the

    new one. Supplying the version you read is what makes an update a

    compare-and-swap. Omitting it for an object that already exists is

    `precondition_failed`, the same as a lost race, and both carry the

    `version` to retry with. There is no blind overwrite, with one exception:

    `message.update` changes read state, labels and folder without a version,

    and its `labels` replace the message's labels whole, so two agents

    labelling one message at once keep only the last write.


    ## Idempotency


    `POST /v1/send` and the create, update and delete operations accept

    `idempotency_key`. A repeat with the same key returns the first attempt's

    result rather than doing the work again. A repeat that arrives while the

    first attempt is still running is refused as `rate_limited`, with

    `retry_after_ms` saying when to ask again. A key belongs to the agent that

    sent it, and a refused or failed attempt does not spend it.


    | operation | a repeat with the same key |

    | --- | --- |

    | `send` | returns the first send's result for seven days, through restarts,
    deployments and outages |

    | every other write | is recognised on a best-effort basis for up to an hour
    |


    Outside `send`, a key can be forgotten sooner: after a service

    interruption, or while the service is under heavy load. A forgotten key

    does the work again, exactly as if no key had been sent; it never returns

    the result of a different request. Treat the key as protection against the

    retry you make straight after a timeout, and make a retried create safe to

    repeat: read before retrying, or delete the extra object.


    A key names one request. Never reuse one for a different request: on a

    create, update or delete such a reuse is refused as `invalid`.
servers:
  - url: https://bud.noetive.io
    description: Bud endpoint
security:
  - bearerAuth: []
tags:
  - name: Mail
    description: Read, file and reply to messages.
  - name: Send
    description: Compose and send, with drafts and approval holds.
  - name: Calendar
    description: Calendars, events and free/busy.
  - name: Contacts
    description: Addressbooks and contacts.
  - name: Attachments
    description: Parts of received messages, and blobs to attach to sent ones.
  - name: Events
    description: The live stream of what happened.
  - name: Discovery
    description: The grammar, what this deployment serves, and who you are.
  - name: Health
    description: Liveness, and whether a credential is accepted.
paths:
  /v1/me.describe:
    post:
      tags:
        - Discovery
      summary: Who this credential is
      description: |
        The agent, its addresses, its mailbox, calendars and addressbook,
        and what it may reach. The first call a client should make.
      operationId: describeMe
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          $ref: '#/components/responses/Read'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '402':
          $ref: '#/components/responses/NotBillable'
        '503':
          $ref: '#/components/responses/UpstreamUnavailable'
components:
  responses:
    Read:
      description: The object.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ReadResult'
    Unauthorized:
      description: |
        The credential is missing, unknown, revoked or expired. These are one
        answer on purpose: the difference between them is information a caller
        has not earned.

        This is the only refusal that means the credential itself does not
        work. Stop presenting it.
      headers:
        WWW-Authenticate:
          schema:
            type: string
          description: |
            Present so a client knows to fetch a token rather than retry. Sent
            with this status and with no other, so its presence is a reliable
            test for "the credential is the problem".
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
    NotBillable:
      description: |
        The credential is good and the account behind it cannot incur usage.
        Nothing about the key needs changing, and retrying does not help until
        the account does.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
    UpstreamUnavailable:
      description: |
        Something this request needed did not answer. The credential is fine,
        the request had no effect, and it is worth retrying with backoff.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
  schemas:
    ReadResult:
      type: object
      properties:
        ref:
          type: string
          description: What was read, as the server understood it.
        kind:
          type: string
          description: Which shape this is, so a client can branch without re-parsing.
        text:
          type: string
          description: The rendering, for the kinds that have one.
        content:
          type: object
          description: |
            The structured form, for the kinds that have one. Its shape depends
            on `kind`.
        provenance:
          $ref: '#/components/schemas/Provenance'
        cursor:
          type: string
          description: Present when there is more to read.
        error:
          $ref: '#/components/schemas/Error'
    ErrorEnvelope:
      type: object
      required:
        - error
      properties:
        error:
          $ref: '#/components/schemas/Error'
    Provenance:
      type: object
      description: |
        Where the content came from and what was removed from it. Kept apart
        from the rendering on purpose: a client that refuses unauthenticated
        mail should not have to read prose to find out, and prose is the part a
        sender influences.
      properties:
        authenticated:
          type: boolean
          description: Whether the message's sender was verified.
        removed:
          type: array
          items:
            type: string
          description: What was stripped from the content before rendering.
    Error:
      type: object
      required:
        - code
        - message
      properties:
        code:
          type: string
          enum:
            - invalid
            - unauthorized
            - not_billable
            - forbidden_scope
            - not_found
            - precondition_failed
            - policy_refused
            - rate_limited
            - paused
            - upstream_unavailable
            - unavailable
            - internal
        message:
          type: string
          description: What went wrong, in one sentence.
        hint:
          type: string
          description: What to do about it.
        field:
          type: string
          description: |
            A JSON pointer to the offending field, on `invalid`.
          example: /id
        request_id:
          type: string
          description: |
            Correlates this refusal with everything the request caused. The
            same value is on the `X-Request-Id` header. Quote it in a support
            request.
        retry_after_ms:
          type: integer
          description: How long to wait, on `rate_limited`.
        version:
          type: string
          description: The version to retry with, on `precondition_failed`.
        current:
          type: object
          description: |
            Sometimes present on `precondition_failed`: the object as stored.
            Do not rely on it; read the object again when it is absent.
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: |
        Bearer token for one agent. Pass as
        `Authorization: Bearer <token>`.

        A token is shown once when it is issued and is not recoverable
        afterwards. Treat it as a secret: it reaches one agent's mail,
        calendar and contacts, and anything a grant has extended to it.

````