Immersive Commons X402 API

The x402 API from Immersive Commons — 1 operation(s) for x402.

GitHub OpenAPI

Operations 2

GET /m/{handle}/x/{slug} Price an offering (x402 402), or buy one that needs no input #
POST /m/{handle}/x/{slug} Buy a member's offering over x402 #

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/immersivecommons-com:immersivecommons-com-x402-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.

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

immersivecommons-com-x402-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Immersive Commons — Agent REST X402 API
  version: '2026-09-15'
  summary: The REST surface an AI agent uses to act at Immersive Commons.
  description: 'Machine-readable description of the Immersive Commons REST API for AI agents.


    **Authentication.** Most operations take a Bearer agent token (`Authorization: Bearer agt_...`). Mint one via the RFC 8628 device-code flow (`POST /api/agent/signup/start` → poll `/api/agent/signup/poll`) or a human mints it at /floor10/agent-console. Tokens carry least-privilege scopes; each operation names the scope it needs in its `security` requirement. Public reads allow anonymous access (empty security requirement). A few operations tagged `browser-session` are Clerk-cookie only and are NOT reachable with an agt_ bearer — agents use the equivalent MCP tools instead.


    **Error model.** Operation errors return JSON that validates against the shared `Error` schema (`{ "error": "..." }`, optionally `ok:false`/`error_kind`/`rate`/`retry_after_seconds`). Any /api/* path that matches NO operation returns the catch-all floor — HTTP 401 with `{ "error": { "code", "message" } }` and a `WWW-Authenticate: Bearer resource_metadata=...` header pointing at /.well-known/oauth-protected-resource.


    **Idempotency.** The deduped write operations accept an optional `Idempotency-Key` request header: a retry with the same key replays the first successful result (24h window) instead of creating a second side effect. This layers on top of each endpoint''s own semantic dedupe (e.g. RSVP''s 7-day window).


    **Versioning & deprecation policy.** The API is served UNVERSIONED at the root path (no `/v1` prefix, no per-request version header). The dated `info.version` (CalVer) is the change marker to pin against. An operation scheduled for removal is marked `deprecated: true` here, announced via /developers and llms.txt, and kept at least one release. Deprecated today (2026-09-15, the IC Credits rename): the seven `/api/zai-keys/*` paths, each a byte-identical re-export of its `/api/credits/*` twin (same handler, auth, body and response), so moving is a path change and nothing else. Breaking changes ship under a new dated version; additive changes do not.


    **Rate limits.** Agent tokens are limited per-token per endpoint family (e.g. 3 highlight submissions/day, 60 research queries/hour). 429 responses carry a `Retry-After` header. Responses carry the RFC RateLimit headers (draft-ietf-httpapi-ratelimit-headers: `RateLimit` + `RateLimit-Policy` in RFC 9651 Structured Fields syntax, plus the legacy discrete `RateLimit-Limit` / `RateLimit-Remaining` / `RateLimit-Reset`) so callers can self-throttle. These are live on the anonymous-reachable reads AND on auth rejections (401/403) — an unauthenticated request still consumes the anonymous budget (default policy: 120 requests / 60s window), so the conventions are verifiable without a token.'
  contact:
    name: Immersive Commons
    email: admin@immersivecommons.com
    url: https://www.immersivecommons.com/developers
  license:
    name: Proprietary
    url: https://www.immersivecommons.com/privacy
servers:
- url: https://www.immersivecommons.com
  description: Production
- url: https://www.immersivecommons.com
  description: Sandbox (test mode) — same base URL; mint a sandbox token via `sandbox:true` on /api/agent/signup/start. Writes return simulated receipts, reads serve real data.
  x-sandbox: token-flag
security:
- {}
tags:
- name: X402
paths:
  /m/{handle}/x/{slug}:
    get:
      operationId: buyOfferingGet
      tags:
      - X402
      summary: Price an offering (x402 402), or buy one that needs no input
      description: 'An x402 v2 resource (coinbase/x402 specs/transports-v2/http.md). Without a payment header it answers 402 with PaymentRequirements (in the PAYMENT-REQUIRED header and the body) whose payTo is the SELLING MEMBER''s own address: Base USDC (exact, EIP-3009) and, when the member takes it, Solana USDC (exact, fee payer from the CDP facilitator). Retry with PAYMENT-SIGNATURE (or the v1 X-PAYMENT) header: IC checks the payment itself, settles through the CDP facilitator straight into the member''s wallet, fulfils (file link, booking, paid inbox message, the member''s webhook, or manual) and returns the receipt with PAYMENT-RESPONSE / X-PAYMENT-RESPONSE. The same payment replayed returns the same receipt and is never fulfilled twice. A fulfilment that fails after settlement still returns the receipt (status fulfilment_failed); the member is told. 202 = settlement_pending: retry the same request, never pay again. IC holds no funds and takes no fee. Unknown handle, unknown slug, paused and taken-down offerings all answer the same 404. MCP discovery: `ic_offerings_get`. 404 unless offerings are enabled.'
      security:
      - {}
      parameters:
      - name: handle
        in: path
        required: true
        schema:
          type: string
          maxLength: 64
        description: The selling member's IC handle.
      - name: slug
        in: path
        required: true
        schema:
          type: string
          pattern: ^[a-z0-9][a-z0-9-]{0,47}$
        description: The offering's slug.
      - name: amount
        in: query
        required: false
        schema:
          type: string
        description: 'pay_what_you_want only: the decimal USDC you choose to pay, at least the minimum.'
      - name: quantity
        in: query
        required: false
        schema:
          type: integer
          minimum: 1
          maximum: 1000
        description: 'per_unit only: how many units.'
      - name: network
        in: query
        required: false
        schema:
          type: string
          enum:
          - base
          - solana
        description: Advertise only this network.
      - name: PAYMENT-SIGNATURE
        in: header
        required: false
        schema:
          type: string
        description: Base64 x402 PaymentPayload (v2). X-PAYMENT is accepted too.
      responses:
        '200':
          description: 'Paid, settled and fulfilled (or fulfilment_failed): the receipt and the result.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OfferingReceiptResponse'
        '202':
          description: 'settlement_pending: the payment was broadcast; retry the same request with the same payment.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OfferingPendingResponse'
        '400':
          description: Bad ?amount / ?quantity / ?network, or input invalid for this offering's kind (not charged).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '402':
          description: 'Payment required, or the payment did not match: the body is x402 v2 PaymentRequired { x402Version, error, resource, accepts[] (payTo = the member''s own address) } plus offering, input and amount_usdc (schema OfferingPaymentRequired); the PAYMENT-REQUIRED header carries the same object.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Members-only offering and you are not an IC member, or the member does not accept messages from you (not charged).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: No such offering on sale, or offerings are not enabled.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: This payment is already being processed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '410':
          description: Sold out.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Per-buyer daily limit reached (not charged).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '502':
          description: The facilitator reported a different payer.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '503':
          description: Payments unavailable right now.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      x-ic-route:
        file: app/(marketing)/m/[handle]/x/[slug]/route.ts
        method: GET
    post:
      operationId: buyOffering
      tags:
      - X402
      summary: Buy a member's offering over x402
      description: 'An x402 v2 resource (coinbase/x402 specs/transports-v2/http.md). Without a payment header it answers 402 with PaymentRequirements (in the PAYMENT-REQUIRED header and the body) whose payTo is the SELLING MEMBER''s own address: Base USDC (exact, EIP-3009) and, when the member takes it, Solana USDC (exact, fee payer from the CDP facilitator). Retry with PAYMENT-SIGNATURE (or the v1 X-PAYMENT) header: IC checks the payment itself, settles through the CDP facilitator straight into the member''s wallet, fulfils (file link, booking, paid inbox message, the member''s webhook, or manual) and returns the receipt with PAYMENT-RESPONSE / X-PAYMENT-RESPONSE. The same payment replayed returns the same receipt and is never fulfilled twice. A fulfilment that fails after settlement still returns the receipt (status fulfilment_failed); the member is told. 202 = settlement_pending: retry the same request, never pay again. IC holds no funds and takes no fee. Unknown handle, unknown slug, paused and taken-down offerings all answer the same 404. MCP discovery: `ic_offerings_get`. 404 unless offerings are enabled.'
      security:
      - {}
      parameters:
      - name: handle
        in: path
        required: true
        schema:
          type: string
          maxLength: 64
        description: The selling member's IC handle.
      - name: slug
        in: path
        required: true
        schema:
          type: string
          pattern: ^[a-z0-9][a-z0-9-]{0,47}$
        description: The offering's slug.
      - name: amount
        in: query
        required: false
        schema:
          type: string
        description: 'pay_what_you_want only: the decimal USDC you choose to pay, at least the minimum.'
      - name: quantity
        in: query
        required: false
        schema:
          type: integer
          minimum: 1
          maximum: 1000
        description: 'per_unit only: how many units.'
      - name: network
        in: query
        required: false
        schema:
          type: string
          enum:
          - base
          - solana
        description: Advertise only this network.
      - name: PAYMENT-SIGNATURE
        in: header
        required: false
        schema:
          type: string
        description: Base64 x402 PaymentPayload (v2). X-PAYMENT is accepted too.
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OfferingBuyInput'
      responses:
        '200':
          description: 'Paid, settled and fulfilled (or fulfilment_failed): the receipt and the result.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OfferingReceiptResponse'
        '202':
          description: 'settlement_pending: the payment was broadcast; retry the same request with the same payment.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OfferingPendingResponse'
        '400':
          description: Bad ?amount / ?quantity / ?network, or input invalid for this offering's kind (not charged).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '402':
          description: 'Payment required, or the payment did not match: the body is x402 v2 PaymentRequired { x402Version, error, resource, accepts[] (payTo = the member''s own address) } plus offering, input and amount_usdc (schema OfferingPaymentRequired); the PAYMENT-REQUIRED header carries the same object.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Members-only offering and you are not an IC member, or the member does not accept messages from you (not charged).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: No such offering on sale, or offerings are not enabled.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: This payment is already being processed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '410':
          description: Sold out.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Per-buyer daily limit reached (not charged).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '502':
          description: The facilitator reported a different payer.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '503':
          description: Payments unavailable right now.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      x-ic-route:
        file: app/(marketing)/m/[handle]/x/[slug]/route.ts
        method: POST
components:
  schemas:
    OfferingReceiptResponse:
      type: object
      required:
      - ok
      - receipt
      - fulfilment
      properties:
        ok:
          type: boolean
        receipt:
          $ref: '#/components/schemas/OfferingReceipt'
        fulfilment:
          type: object
          properties:
            ok:
              type: boolean
            message:
              type: string
        result:
          type: object
          additionalProperties: true
          description: 'What was bought: download_url, booking, thread_id, the member endpoint''s response, or instructions.'
        replayed:
          type: boolean
          description: 'true when this payment had already been settled: the stored receipt, nothing re-fulfilled.'
    OfferingBuyInput:
      type: object
      additionalProperties: true
      description: 'By kind. message: { message, from_name?, reply_to? }. booking: { start, name, email, note?, hold_token? }. manual: { note?, contact? }. webhook: any JSON (forwarded as `input`). file: none.'
    OfferingPendingResponse:
      type: object
      properties:
        ok:
          type: boolean
        status:
          type: string
        tx_hash:
          type:
          - string
          - 'null'
        message:
          type: string
    OfferingReceipt:
      type: object
      required:
      - receipt_id
      - offering_id
      - member
      - buyer_address
      - amount
      - network
      - status
      properties:
        receipt_id:
          type: string
          description: rcp_...
        offering_id:
          type: string
        offering_slug:
          type: string
        offering_title:
          type: string
        member:
          type: string
          description: The seller's handle.
        buyer_address:
          type: string
        amount:
          type: string
          description: Decimal USDC.
        amount_atomic:
          type: string
        asset:
          type: string
          const: USDC
        network:
          type: string
          enum:
          - base
          - solana
        network_caip2:
          type: string
        network_mode:
          type: string
          enum:
          - testnet
          - mainnet
        tx_hash:
          type:
          - string
          - 'null'
        via:
          type: string
          enum:
          - x402
          - member_wallet
        status:
          type: string
          enum:
          - fulfilled
          - fulfilment_failed
        fulfilled_at:
          type:
          - string
          - 'null'
          format: date-time
        created_at:
          type: string
          format: date-time
        result:
          type: object
          additionalProperties: true
        fulfilment_error:
          type: string
    Error:
      type: object
      required:
      - error
      additionalProperties: true
      description: Structured JSON error. `error` (string) is always present — an error code or a human-readable message. `ok:false` is present on bearer auth-gate rejections. Endpoints may attach additional context keys to aid recovery (tier, current_tier, limit, window_seconds, valid_kinds, recovery_hint, detail, example, ...); the reusable ones are named below.
      properties:
        error:
          type: string
          description: Error code or human-readable message (always present).
        ok:
          type: boolean
          enum:
          - false
          description: Present (false) on auth-gate rejections.
        error_kind:
          type: string
          description: Machine-readable failure class (rate_limit, validation, not_found, ...).
        message:
          type: string
          description: Longer human-readable detail (feedback + some rate-limit errors).
        rate:
          $ref: '#/components/schemas/RateInfo'
        retry_after_seconds:
          type: integer
          description: Seconds to wait before retrying (on 429).
        tier:
          type: string
          description: The caller's current tier — present on a tier/scope authorization (403) rejection.
        current_tier:
          type: string
          description: The caller's current tier — present on a tier/request validation (400) rejection.
        detail:
          type: string
          description: Extra failure detail — present on some 500 responses (e.g. the agent event-log read).
    RateInfo:
      type: object
      description: Per-token rate-limit snapshot returned by write endpoints.
      properties:
        current:
          type: integer
        remaining:
          type: integer
        limit:
          type: integer
  securitySchemes:
    agentBearer:
      type: http
      scheme: bearer
      bearerFormat: agt_<base64url>
      description: 'Per-member, individually-revocable agent token minted via the device-code flow. Send as `Authorization: Bearer agt_...`. The scope array in each operation''s security requirement names the IC scope the handler enforces.'
    clerkSession:
      type: apiKey
      in: cookie
      name: __session
      description: Browser Clerk session cookie. Operations under this scheme are reachable ONLY from a signed-in browser session, NOT with an agt_ bearer token. Agents use the equivalent MCP tools (e.g. ic_get_my_membership, ic_request_tier).
    workshopCode:
      type: http
      scheme: bearer
      bearerFormat: 6-char enrollment code
      description: 'The workshop''s own enrollment code, minted by POST /api/workshop/enroll and presented as a bearer. It is NOT an agt_ token: it carries no scopes, is not revocable per-token, and reaches only the /api/workshop/* routes.'
    sliceServiceSecret:
      type: http
      scheme: bearer
      bearerFormat: shared secret
      description: SLICE_SERVICE_SECRET — the machine-to-machine bearer the print-slicing service presents. A distinct trust boundary (an external machine on the tailnet), which is why it has its own secret rather than reusing the cron one. No member holds it and no member-facing flow can reach these routes.
    floorcastOnboarding:
      type: http
      scheme: bearer
      bearerFormat: fco_<...>
      description: 'A single-use Floorcast onboarding token. It exists because tenant provisioning has a chicken-and-egg problem: no operator exists yet for a floor that does not exist yet, so neither a Clerk session nor an agt_ token can authorize the call. Minting one is a concierge step with no live route, and the token is consumed by the provision it authorizes.'
x-payment-info:
  protocol: x402
  discovery: https://www.immersivecommons.com/discovery/resources
  donor_wall: https://www.immersivecommons.com/api/floor10/donations
  note: Payable resources are advertised at /discovery/resources; a bare request to a payable resource returns HTTP 402 with the PAYMENT-REQUIRED challenge.
x-api-lifecycle:
  versioning: unversioned-root (info.version is a dated CalVer change marker)
  deprecation: 'deprecated operations are flagged `deprecated: true` here and kept at least one release; the /api/zai-keys/* aliases (2026-09-15) are the current set'
x-sandbox:
  summary: 'A sandbox token (mint by adding "sandbox": true to POST /api/agent/signup/start) is a real token with real scopes whose WRITE operations return a simulated receipt instead of mutating; reads serve real data. Same base URL + bearer auth. Immutable after mint.'
  obtain:
    endpoint: POST /api/agent/signup/start
    body:
      sandbox: true
  write_response_shape:
    ok: true
    sandbox: true
    simulated: true
    would_have:
      action: string
      scope: string
      args: object
    note: string — scope was checked; deeper business rules (tier/role/ownership/signature) are NOT evaluated in sandbox, and no production state changed. A green receipt means well-formed + scoped, NOT guaranteed to pass in production.
  real_exceptions:
  - POST /api/agent/feedback (bug-report channel must be heard)
  - POST /api/agent/token/revoke (token lifecycle; genuinely revokes)
  not_sandbox_eligible:
  - ic_donate (x402 payment rail — never faked; not a REST operation in this spec)
  - floor-admin toggles + tools with no concrete scope to check — denied fail-closed, never silently simulated