bubblio-dev Platform Push API

Signed platform → Bubblio pushes (late results, payment-link settlements).

Operations 2

POST /v1/agent-door/results/{quoteId} Push a late result onto a quote (unreachable → ok) #
POST /v1/agent-door/paid/{quoteId} Mark a quote's payment settled (the payment-link rail's resume, #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/bubblio-dev:bubblio-dev-platform-push-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

bubblio-dev-platform-push-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Bubblio Dev Platform Push API
  version: 1.0.0
  contact:
    email: bubblio@andresio.com
  description: 'Operations tagged platform-push across 2 of this provider''s published API definitions: openapi.yaml, bubblio-dev-openapi.yaml. Each path carries the servers of the definition it was published in.'
servers:
- url: https://api.bubblio.dev
  description: Hosted production platform — the canonical host.
- url: https://andresomar95--bubblio-api-serve.modal.run
  description: The same deployment under its infrastructure name (the SDK's default BUBBLIO_API_URL).
tags:
- name: platform-push
  description: Signed platform → Bubblio pushes (late results, payment-link settlements).
paths:
  /v1/agent-door/results/{quoteId}:
    post:
      tags:
      - platform-push
      summary: Push a late result onto a quote (unreachable → ok)
      description: 'The >20s escape hatch (the SDK''s `pushDoorResult`; `createBubblioToolRoute` calls

        it automatically when a handler outlives the callback window). Requires the SIGNED

        push (API key + V2 signature over `${timestamp}.${rawBody}` with the platform''s

        webhook secret) and the signed body must name this same quote — a captured push for

        quote A can never replay against quote B. Only `unreachable → ok` exists: an

        answered attempt is final, and a late FAILURE has nothing to push. The upgrade is

        APPEND-shaped (original receipt fields survive verbatim; `result_received_at`

        records the landing). A pushed `payment` summary must match the quote''s pinned

        price exactly — amounts on receipts are never rewritable — and may never carry a

        credential (any surplus field is refused).'
      operationId: pushDoorResult
      security:
      - apiKey: []
      parameters:
      - $ref: '#/components/parameters/quoteId'
      - $ref: '#/components/parameters/signatureV2'
      - $ref: '#/components/parameters/timestamp'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - quoteId
              - result
              properties:
                quoteId:
                  $ref: '#/components/schemas/QuoteId'
                result:
                  type: object
                  description: ≤32KB serialized — refused (not truncated) over the cap.
                payment:
                  $ref: '#/components/schemas/PaymentSummary'
      responses:
        '200':
          description: Receipt upgraded unreachable → ok.
          content:
            application/json:
              schema:
                type: object
        '400':
          $ref: '#/components/responses/CalmBadRequest'
        '404':
          description: 'UNIFORM: unknown quote, malformed id, stale/absent timestamp, or a signature

            that did not verify — all read the same body (`RESULT_PUSH_MISS`): "No quote

            accepts a result push here. Either the quote id is unknown, or the push was

            not signed correctly — check the webhook secret, the X-Bubblio-Timestamp

            freshness, and that the signed body carries this same quoteId." (Probing

            resistance: a rotation-stale secret is indistinguishable from a wrong quote

            id; the SDK refreshes its cached secret once and retries on this answer.)

            '
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CalmError'
        '409':
          description: '`code: already_resolved` (benign — the callback made it in time), `not_confirmed`, or `final_outcome`.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CalmError'
        '413':
          description: Body over 64KB / result over 32KB.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CalmError'
    servers:
    - url: https://api.bubblio.dev
      description: Hosted production platform — the canonical host.
    - url: https://andresomar95--bubblio-api-serve.modal.run
      description: The same deployment under its infrastructure name (the SDK's default BUBBLIO_API_URL).
  /v1/agent-door/paid/{quoteId}:
    post:
      tags:
      - platform-push
      summary: Mark a quote's payment settled (the payment-link rail's resume,
      description: 'Called from the platform''s `checkout.session.completed` webhook (the SDK''s

        `resumePaidQuote` / `completeBubblioCheckout`). Same signed-push authentication as

        the results endpoint. Bubblio refuses a settlement whose `args_hash` or amount

        doesn''t match the quote''s pin — the money must buy exactly the pinned call — and

        every refund-worthy refusal means the payment bought nothing (the SDK auto-refunds

        it on the platform''s own Stripe). After a settle, the visiting agent''s next confirm

        poll executes the action, payment already made.'
      operationId: resumePaidQuote
      security:
      - apiKey: []
      parameters:
      - $ref: '#/components/parameters/quoteId'
      - $ref: '#/components/parameters/signatureV2'
      - $ref: '#/components/parameters/timestamp'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - quoteId
              - payment
              properties:
                quoteId:
                  $ref: '#/components/schemas/QuoteId'
                args_hash:
                  type: string
                  description: The session's metadata.args_hash — must match the pin.
                payment:
                  $ref: '#/components/schemas/PaymentSummary'
      responses:
        '200':
          description: 'Settled (with `already: true` on a webhook redelivery — benign).'
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  already:
                    type: boolean
        '400':
          description: Malformed, or a coded mismatch (`amount_mismatch`, `args_mismatch`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CalmError'
        '404':
          description: Uniform miss (unknown quote / failed signature), same doctrine as the results push.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CalmError'
        '409':
          description: 'Coded refusal: `expired`, `already_settled`, `not_payable`, or `conflict` (transient race — the webhook redelivery decides).'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CalmError'
        '413':
          description: Body over 16KB.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CalmError'
    servers:
    - url: https://api.bubblio.dev
      description: Hosted production platform — the canonical host.
    - url: https://andresomar95--bubblio-api-serve.modal.run
      description: The same deployment under its infrastructure name (the SDK's default BUBBLIO_API_URL).
webhooks:
  toolCallback:
    post:
      tags:
      - platform-push
      summary: The signed action/tool callback POSTed to the platform's callbackUrl
      description: 'What `createBubblioToolRoute` receives and verifies. Signed twice for one

        deprecation window — the replay-protected `X-Bubblio-Signature-V2` (HMAC-SHA256

        over `${timestamp}.${rawBody}`) is the one to verify; the legacy body-only

        `X-Bubblio-Signature` is replayable and refused by SDK ≥0.9 unless explicitly

        allowed. Delivered AT MOST ONCE per quote — there is no retry loop, and a duplicate

        confirm replays the stored receipt without reaching the platform (#49: handler-side

        replay caches are defense-in-depth, not the primary double-execution defense).


        Bubblio waits at most `min(timeoutSeconds ?? 10, 20)` seconds; a slower handler

        strands the receipt at `unreachable` until a signed results push resolves it.


        Expected responses: 200 with the JSON result (outcome `ok`); any non-2xx finalizes

        the receipt as `platform_rejected`. For a `paymentLinkRequest` body (a quote-time

        mint, no tool dispatch), answer `{ url, ref }`.'
      parameters:
      - name: X-Bubblio-Signature-V2
        in: header
        required: true
        schema:
          type: string
      - name: X-Bubblio-Timestamp
        in: header
        required: true
        schema:
          type: string
      - name: X-Bubblio-Signature
        in: header
        schema:
          type: string
        description: Legacy body-only signature (compat; do not verify against it).
      - name: X-Bubblio-Session
        in: header
        schema:
          type: string
      - name: X-Bubblio-Tool
        in: header
        schema:
          type: string
      - name: X-Bubblio-Dangerous
        in: header
        schema:
          type: string
          const: 'true'
        description: Present on tools the platform classified destructive.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CallbackBody'
      responses:
        '200':
          description: The handler's JSON result — stored on the receipt (≤32KB).
    servers:
    - url: https://api.bubblio.dev
      description: Hosted production platform — the canonical host.
    - url: https://andresomar95--bubblio-api-serve.modal.run
      description: The same deployment under its infrastructure name (the SDK's default BUBBLIO_API_URL).
components:
  parameters:
    quoteId:
      name: quoteId
      in: path
      required: true
      schema:
        $ref: '#/components/schemas/QuoteId'
    timestamp:
      name: X-Bubblio-Timestamp
      in: header
      required: true
      schema:
        type: string
      description: Unix milliseconds; ±5 minutes tolerated.
    signatureV2:
      name: X-Bubblio-Signature-V2
      in: header
      required: true
      schema:
        type: string
      description: '`sha256=<hmac>` over `${timestamp}.${rawBody}` with the webhook secret.'
  responses:
    CalmBadRequest:
      description: One calm sentence naming the malformed field.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/CalmError'
  schemas:
    CalmError:
      type: object
      required:
      - error
      properties:
        error:
          type: string
        code:
          type: string
          description: Machine-readable refusal code, present where documented — branch on this, never on message text.
    CallbackBody:
      type: object
      description: 'The V2-signed JSON Bubblio POSTs to the platform''s callbackUrl (mirrors the SDK''s

        CallbackBody). Widget-session tool callbacks carry only tool/args (+ sessionId);

        the other fields are Agent Door facts.

        '
      required:
      - tool
      - args
      properties:
        tool:
          type: string
        args:
          type: object
        agent:
          type: object
          description: The visiting-agent identity block on Agent Door confirms.
          properties:
            tier:
              type: string
              enum:
              - keyed
              - anonymous
            keyId:
              type: string
              description: 'Managed-key path: the bak_ key row id (the raw key never travels).'
            key:
              type: string
              description: 'Custom-custody path only: the platform-minted raw key, passed through verbatim and never validated by Bubblio.'
            verified_agent:
              type: string
              description: The Web-Bot-Auth-VERIFIED operator origin, when the quote proved one (#42).
        ctx:
          type: string
          description: 'The platform-signed user-context JWT, inside the signed body (≥0.10; also

            echoed as `?ctx=` on the URL for a deprecation window). Bubblio stores it

            encrypted and cannot verify or forge it.

            '
        idempotencyKey:
          type: string
          description: 'The quote id, on Agent Door confirms — the charge idempotency key and the

            handle a timed-out quote is resolved by (`snake_case` alias

            `idempotency_key` tolerated). Delivered at most once per quote — see the

            webhook description for the honest framing.

            '
        callbackTimeoutSeconds:
          type: number
          description: How long Bubblio waits on THIS delivery before recording `unreachable` (platforms ≥0.10).
        payment:
          type: object
          description: 'The charge instruction on a PAID confirm — `{ rail, token, amount_cents,

            currency, args_hash? }`. Amount/currency are the QUOTE''S PIN (the agent can

            never set an amount); the token is transit-only and must never be stored or

            logged. Raw card numbers are hard-refused at both ends.

            '
        payment_settled:
          $ref: '#/components/schemas/PaymentSummary'
          description: Settlement FACTS on a confirm whose payment already landed out-of-band (payment-link) — nothing to charge.
        paymentLinkRequest:
          type: object
          description: 'A quote-time request to mint the Stripe Checkout link on the PLATFORM''S OWN

            account — `{ quoteId, amount_cents, currency, expires_at?, label?, tool?,

            args_hash? }`. Handled before tool dispatch; the expected answer is

            `{ url, ref }`.

            '
    QuoteId:
      type: string
      pattern: ^q_[a-f0-9]{16}(?:[a-f0-9]{16})?$
    PaymentSummary:
      type: object
      description: The settled charge as receipts carry it — facts only, never a credential.
      required:
      - rail
      - amount_cents
      - currency
      - ref
      properties:
        rail:
          type: string
          examples:
          - stripe_spt
          - payment_link
        amount_cents:
          type: integer
        currency:
          type: string
        ref:
          type: string
          description: The provider reference (Stripe PaymentIntent / Checkout Session id).
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      description: The platform's Bubblio API key (`bbl_…`). Server-side only.
    consentToken:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: The human's passkey-session token from `POST /approvals/session`.
x-refined-from:
- openapi.yaml
- bubblio-dev-openapi.yaml