Ultravioleta DAO Escrow API

x402r on-chain escrow — lock, release, refund across 9 EVM chains.

Operations 9

GET /api/v1/escrow/config Get Escrow Config #
GET /api/v1/escrow/payment-extension Get Payment Extension #
GET /api/v1/escrow/deposits/{deposit_id} Get Deposit #
GET /api/v1/escrow/balance Get Merchant Balance #
POST /api/v1/escrow/release Release To Worker #
POST /api/v1/escrow/refund Refund To Agent #
GET /api/v1/escrow/task/{task_id}/reclaim Reclaim data for the task's payer (unsigned calldata) #
GET /api/v1/escrow/task/{task_id}/lifecycle-challenge EIP-712 the payer signs to authorize a release or refund #
POST /api/v1/escrow/task/{task_id}/lifecycle-order Record the payer-signed order that authorizes the release #

Documentation

Specifications

Other Resources

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/execution-market-escrow-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

execution-market-escrow-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Execution Market Escrow API
  description: '## Universal Execution Layer


    Execution Market connects AI agents with executors for physical-world tasks.'
  contact:
    name: Ultravioleta DAO
    url: https://ultravioletadao.xyz/
    email: ultravioletadao@gmail.com
  license:
    name: MIT
    url: https://opensource.org/licenses/MIT
  version: 2.0.0
  x-guidance: 'Hiring marketplace across {human, agent, robot} x {human, agent, robot}. Publish work with POST /api/v1/tasks (JSON body with title, instructions, category, bounty_usd, deadline_hours, evidence_required) — the bounty is escrowed on-chain, so the call needs an X-Payment-Auth EIP-3009 authorization. Browse open work with GET /api/v1/tasks/available (free, no auth). Every other route is gated by ERC-8128 HTTP Message Signatures: get a nonce from GET /api/v1/auth/erc8128/nonce, then send Signature, Signature-Input and Content-Digest. Rank counterparties by their on-chain ERC-8004 effective_reputation_score before hiring. Full agent guide: https://execution.market/skill.md'
  x-payment-info:
    protocol: x402
    version: '1.0'
    discovery: /.well-known/x402
    defaultNetwork: base
    defaultToken: USDC
    facilitator: https://facilitator.ultravioletadao.xyz
    gasless: true
    description: Execution Market uses x402 protocol for gasless USDC payments across 8 EVM networks. Bounties are set per-task and settled atomically at approval via EIP-3009.
  x-logo:
    url: https://execution.market/logo.png
    altText: Execution Market Logo
servers:
- url: https://api.execution.market
  description: Production server
- url: http://localhost:8000
  description: Local development
security:
- erc8128: []
tags:
- name: Escrow
  description: x402r on-chain escrow — lock, release, refund across 9 EVM chains.
paths:
  /api/v1/escrow/config:
    get:
      tags:
      - Escrow
      summary: Get Escrow Config
      description: 'Get x402r escrow configuration for a network.


        Contract addresses (AuthCaptureEscrow, TokenStore factory, EM

        PaymentOperator, USDC) derived live from the NETWORK_CONFIG registry —

        the single source of truth. Useful for agents to know where funds are

        held.'
      operationId: get_escrow_config_api_v1_escrow_config_get
      parameters:
      - name: network
        in: query
        required: false
        schema:
          type: string
          description: Payment network (e.g. 'base', 'polygon')
          default: base
          title: Network
        description: Payment network (e.g. 'base', 'polygon')
      responses:
        '200':
          description: Escrow configuration
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EscrowConfigResponse'
        '404':
          description: Unknown network or no x402r escrow deployed on it
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /api/v1/escrow/payment-extension:
    get:
      tags:
      - Escrow
      summary: Get Payment Extension
      description: 'Get the x402r refund extension for payment payloads.


        Agents should include this extension when making payments to Execution Market

        to enable trustless refunds via the escrow contract.


        Example usage in x402 payment:

        ```json

        {

        "paymentPayload": {

        "x402Version": 2,

        "accepted": {

        "payTo": "",

        "amount": "10000000"

        },

        "extensions": { ... response from this endpoint ... }

        }

        }

        ```'
      operationId: get_payment_extension_api_v1_escrow_payment_extension_get
      responses:
        '200':
          description: Payment extension for x402
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaymentExtensionResponse'
        '503':
          description: Escrow not configured
  /api/v1/escrow/deposits/{deposit_id}:
    get:
      tags:
      - Escrow
      summary: Get Deposit
      description: 'Get information about a deposit in escrow.


        Returns the deposit state, payer, amount, and timestamp.'
      operationId: get_deposit_api_v1_escrow_deposits__deposit_id__get
      parameters:
      - name: deposit_id
        in: path
        required: true
        schema:
          type: string
          minLength: 64
          maxLength: 66
          description: Deposit ID (bytes32 hex)
          title: Deposit Id
        description: Deposit ID (bytes32 hex)
      responses:
        '200':
          description: Deposit info
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DepositResponse'
        '404':
          description: Deposit not found
        '503':
          description: Escrow not available
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /api/v1/escrow/balance:
    get:
      tags:
      - Escrow
      summary: Get Merchant Balance
      description: 'Get the USDC balance held in escrow for a merchant.


        If no merchant address is provided, returns Execution Market''s balance.'
      operationId: get_merchant_balance_api_v1_escrow_balance_get
      parameters:
      - name: merchant
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          description: Merchant address (defaults to Execution Market's address)
          title: Merchant
        description: Merchant address (defaults to Execution Market's address)
      responses:
        '200':
          description: Merchant balance
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BalanceResponse'
        '503':
          description: Escrow not available
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /api/v1/escrow/release:
    post:
      tags:
      - Escrow
      summary: Release To Worker
      description: 'Release escrowed funds to a worker.


        **Deprecated**: Use `POST /api/v1/submissions/{id}/approve` instead.

        The approval endpoint handles settlement via the x402 facilitator (gasless).


        This legacy endpoint calls the escrow contract directly (agent pays gas).'
      operationId: release_to_worker_api_v1_escrow_release_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReleaseRequest'
        required: true
      responses:
        '200':
          description: Release executed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReleaseResponse'
        '401':
          description: Unauthorized
        '400':
          description: Invalid request
        '503':
          description: Escrow not available
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      deprecated: true
  /api/v1/escrow/refund:
    post:
      tags:
      - Escrow
      summary: Refund To Agent
      description: 'Refund escrowed funds to the original payer (agent).


        **Requires authentication**: Only the Execution Market backend can refund.


        Uses the x402 SDK + facilitator (gasless) as the primary path.

        Falls back to direct contract call only if the SDK is unavailable.


        This is called when:

        1. Task is cancelled

        2. Dispute resolved in agent''s favor

        3. No worker accepted the task before deadline'
      operationId: refund_to_agent_api_v1_escrow_refund_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RefundRequest'
        required: true
      responses:
        '200':
          description: Refund executed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RefundResponse'
        '401':
          description: Unauthorized
        '503':
          description: Escrow not available
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /api/v1/escrow/task/{task_id}/reclaim:
    get:
      tags:
      - Escrow
      summary: Reclaim data for the task's payer (unsigned calldata)
      description: 'Everything the PAYER of a task escrow needs to recover locked funds themselves: escrow address, chain id, ABI-encoded `reclaim(PaymentInfo)` calldata and the instant it becomes eligible. **EM never signs and never sends this transaction** — the payer submits it from their own wallet, which is what makes the hatch trustless: it works even if EM is down, malicious or refuses.


        Use this when a task expired or was cancelled and the refund window (`refundExpiry`) already closed, so the operator''s refund reverts. `reclaim` is `onlySender(info.payer)` and requires `block.timestamp > authorizationExpiry`.


        Payer-only: the response carries the signed escrow authorization.'
      operationId: get_task_reclaim_api_v1_escrow_task__task_id__reclaim_get
      parameters:
      - name: task_id
        in: path
        required: true
        schema:
          type: string
          pattern: ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$
          description: Task UUID
          title: Task Id
        description: Task UUID
      responses:
        '200':
          description: Calldata the payer can submit
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
                title: Response Get Task Reclaim Api V1 Escrow Task  Task Id  Reclaim Get
        '403':
          description: Caller is not the payer
        '404':
          description: No task escrow found
        '409':
          description: Already settled, nothing to reclaim, or unencodable
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      security: []
  /api/v1/escrow/task/{task_id}/lifecycle-challenge:
    get:
      tags:
      - Escrow
      summary: EIP-712 the payer signs to authorize a release or refund
      description: 'The exact `LifecycleOrder` typed data the escrow''s payer must sign so the Facilitator accepts a `release` (or a `refundInEscrow` from the receiver). **Read-only: it authorizes nothing and moves nothing.**


        `release` and `refundInEscrow` move money that is ALREADY deposited, so neither carries an ERC-3009 authorization — this order is what answers *who may ask for the move*. Policy is the Facilitator''s: `release` is signed by the payer; `refundInEscrow` by the receiver, or by the payer once `authorizationExpiry` has passed.


        Sign the `typed_data` with the wallet that funded the escrow and POST it back to `/lifecycle-order` (or send it as `lifecycle_order` in the approve body). The order expires in 10 minutes: it authorizes one move, not a standing permission.'
      operationId: get_lifecycle_challenge_api_v1_escrow_task__task_id__lifecycle_challenge_get
      parameters:
      - name: task_id
        in: path
        required: true
        schema:
          type: string
          pattern: ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$
          description: Task UUID
          title: Task Id
        description: Task UUID
      - name: action
        in: query
        required: false
        schema:
          type: string
          pattern: ^(release|refundInEscrow)$
          description: '''release'' or ''refundInEscrow'''
          default: release
          title: Action
        description: '''release'' or ''refundInEscrow'''
      responses:
        '200':
          description: Typed data to sign
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
                title: Response Get Lifecycle Challenge Api V1 Escrow Task  Task Id  Lifecycle Challenge Get
        '403':
          description: Caller is neither the payer nor the receiver
        '404':
          description: No task escrow found
        '409':
          description: Already settled, or the escrow cannot be signed over
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      security: []
  /api/v1/escrow/task/{task_id}/lifecycle-order:
    post:
      tags:
      - Escrow
      summary: Record the payer-signed order that authorizes the release
      description: 'Verify a `LifecycleOrder` signed by the payer (or, for `refundInEscrow`, by the receiver) and store it next to the escrow. The next release for this task attaches it to the Facilitator call.


        **Verification is not a formality**: the typed data is rebuilt server-side from the escrow''s own `paymentInfo` and the amount that will actually be sent, never from anything the caller asserts. An order signed over a different struct recovers a *different, valid* address — so the check that carries the guarantee is that the recovered address is the one the Facilitator''s role table accepts.


        Idempotent per order: posting the same signature again is a no-op.'
      operationId: post_lifecycle_order_api_v1_escrow_task__task_id__lifecycle_order_post
      parameters:
      - name: task_id
        in: path
        required: true
        schema:
          type: string
          pattern: ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$
          description: Task UUID
          title: Task Id
        description: Task UUID
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/LifecycleOrderRequest'
      responses:
        '200':
          description: Order verified and stored
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
                title: Response Post Lifecycle Order Api V1 Escrow Task  Task Id  Lifecycle Order Post
        '400':
          description: The order does not verify for this escrow
        '404':
          description: No task escrow found
        '409':
          description: Already settled, or the escrow cannot be signed over
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
components:
  schemas:
    BalanceResponse:
      properties:
        merchant:
          type: string
          title: Merchant
          description: Merchant wallet address
        balance_usdc:
          type: string
          title: Balance Usdc
          description: Total USDC balance held in escrow
        network:
          type: string
          title: Network
          description: Blockchain network
      type: object
      required:
      - merchant
      - balance_usdc
      - network
      title: BalanceResponse
      description: Merchant balance in escrow.
    ReleaseRequest:
      properties:
        deposit_id:
          type: string
          maxLength: 66
          minLength: 64
          title: Deposit Id
          description: Deposit ID (bytes32 hex, with or without 0x prefix)
        worker_address:
          type: string
          maxLength: 42
          minLength: 40
          title: Worker Address
          description: Worker's wallet address
        amount:
          type: string
          title: Amount
          description: Amount to release in USDC (e.g., '10.00')
      type: object
      required:
      - deposit_id
      - worker_address
      - amount
      title: ReleaseRequest
      description: Request to release funds from escrow.
    ReleaseResponse:
      properties:
        success:
          type: boolean
          title: Success
          description: Whether the release was successful
        tx_hash:
          anyOf:
          - type: string
          - type: 'null'
          title: Tx Hash
          description: Transaction hash of the release
        deposit_id:
          type: string
          title: Deposit Id
          description: Deposit ID that was released
        recipient:
          type: string
          title: Recipient
          description: Worker address that received funds
        amount:
          type: string
          title: Amount
          description: Amount released in USDC
        error:
          anyOf:
          - type: string
          - type: 'null'
          title: Error
          description: Error message if release failed
      type: object
      required:
      - success
      - deposit_id
      - recipient
      - amount
      title: ReleaseResponse
      description: Result of release operation.
    PaymentExtensionResponse:
      properties:
        refund:
          additionalProperties: true
          type: object
          title: Refund
          description: Refund extension configuration for x402 payment payloads
      type: object
      required:
      - refund
      title: PaymentExtensionResponse
      description: x402r payment extension for agents.
    EscrowConfigResponse:
      properties:
        available:
          type: boolean
          title: Available
          description: Whether x402r escrow is available
        network:
          type: string
          title: Network
          description: Blockchain network (e.g. 'base')
        chain_id:
          type: integer
          title: Chain Id
          description: EVM chain ID (e.g. 8453 for Base)
        factory_address:
          type: string
          title: Factory Address
          description: TokenStore factory contract address (EIP-1167 clones)
        escrow_address:
          type: string
          title: Escrow Address
          description: AuthCaptureEscrow contract address (holds locked funds)
        operator_address:
          anyOf:
          - type: string
          - type: 'null'
          title: Operator Address
          description: EM PaymentOperator address (Fase 5 atomic fee split), None if not deployed on this network
        usdc_address:
          type: string
          title: Usdc Address
          description: USDC token contract address on this network
      type: object
      required:
      - available
      - network
      - chain_id
      - factory_address
      - escrow_address
      - usdc_address
      title: EscrowConfigResponse
      description: x402r escrow configuration, derived live from the NETWORK_CONFIG registry.
    RefundRequest:
      properties:
        deposit_id:
          type: string
          maxLength: 66
          minLength: 64
          title: Deposit Id
          description: Deposit ID (bytes32 hex, with or without 0x prefix)
      type: object
      required:
      - deposit_id
      title: RefundRequest
      description: Request to refund funds to original payer.
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
            - type: string
            - type: integer
          type: array
          title: Location
        msg:
          type: string
          title: Message
        type:
          type: string
          title: Error Type
        input:
          title: Input
        ctx:
          type: object
          title: Context
      type: object
      required:
      - loc
      - msg
      - type
      title: ValidationError
    DepositResponse:
      properties:
        deposit_id:
          type: string
          title: Deposit Id
          description: Unique deposit identifier (bytes32 hex)
        payer:
          type: string
          title: Payer
          description: Address that made the deposit
        merchant:
          type: string
          title: Merchant
          description: Merchant address (Execution Market)
        amount:
          type: string
          title: Amount
          description: Amount in USDC (e.g. '10.00')
        token:
          type: string
          title: Token
          description: Token address used for the deposit
        state:
          type: string
          title: State
          description: 'Deposit state: NON_EXISTENT, IN_ESCROW, RELEASED, or REFUNDED'
        created_at:
          type: string
          title: Created At
          description: Deposit creation timestamp
      type: object
      required:
      - deposit_id
      - payer
      - merchant
      - amount
      - token
      - state
      - created_at
      title: DepositResponse
      description: Information about a deposit in escrow.
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    RefundResponse:
      properties:
        success:
          type: boolean
          title: Success
          description: Whether the refund was successful
        tx_hash:
          anyOf:
          - type: string
          - type: 'null'
          title: Tx Hash
          description: Transaction hash of the refund
        deposit_id:
          type: string
          title: Deposit Id
          description: Deposit ID that was refunded
        payer:
          type: string
          title: Payer
          description: Agent address that received the refund
        amount:
          type: string
          title: Amount
          description: Amount refunded in USDC
        error:
          anyOf:
          - type: string
          - type: 'null'
          title: Error
          description: Error message if refund failed
      type: object
      required:
      - success
      - deposit_id
      - payer
      - amount
      title: RefundResponse
      description: Result of refund operation.
    LifecycleOrderRequest:
      properties:
        action:
          type: string
          title: Action
          description: '''release'' o ''refundInEscrow'' — la accion que la orden autoriza'
          default: release
        signer:
          type: string
          title: Signer
          description: Direccion que firmo (0x…)
        deadline:
          type: integer
          title: Deadline
          description: Unix segundos; techo de 900 s
        nonce:
          type: string
          title: Nonce
          description: bytes32 en hex, uno por orden
        signature:
          type: string
          title: Signature
          description: Firma EIP-712 (0x…, 65 bytes)
      type: object
      required:
      - signer
      - deadline
      - nonce
      - signature
      title: LifecycleOrderRequest
      description: La orden EIP-712 firmada por el payer, tal como la devuelve el SDK.
  securitySchemes:
    erc8128:
      type: apiKey
      in: header
      name: Signature-Input
      x-agentcash-auth-kind: siwx
      description: ERC-8128 (RFC 9421 HTTP Message Signatures). Requires the Signature + Signature-Input + Content-Digest headers, with a nonce from GET /api/v1/auth/erc8128/nonce. See https://execution.market/skill.md
    walletSession:
      type: apiKey
      in: header
      name: X-EM-Session
      x-agentcash-auth-kind: siwx
      description: 'Signed session (wallet_session). A SessionGrant this server builds at POST /api/v1/auth/session/challenge, signed by the wallet and replayed verbatim. For clients that cannot hash a request body and have no clock. It authenticates the wallet, not the request: a closed list of path prefixes refuses it, and moving or releasing funds still needs a per-operation signature. GET /api/v1/auth/info lists both. Disabled unless EM_WALLET_SESSION_ENABLED is on.'
    oauthBearer:
      type: oauth2
      description: 'OAuth 2.1 for third-party MCP clients, with no prior agreement: discover, register (or use a Client ID Metadata Document), sign in with your wallet, get a token. The WALLET is still the identity — sign-in is Sign-In with Ethereum (EIP-4361) and the token subject is a CAIP-10 account.


        Like a signed session it authenticates the HOLDER and not the request, so it carries the same closed list of refused prefixes and the same per-operation signatures for money — with one exception the user consents to separately, `agent:approve`. Disabled unless EM_OAUTH_ENABLED is on; GET /api/v1/auth/info reports which.'
      flows:
        authorizationCode:
          authorizationUrl: https://auth.execution.market/oauth/authorize
          tokenUrl: https://auth.execution.market/oauth/token
          refreshUrl: https://auth.execution.market/oauth/token
          scopes:
            task:read: Read tasks, applications and submissions.
            task:write: Edit a task you published, and assign a worker to it.
            task:cancel: Cancel a task you published.
            worker:apply: Apply to tasks as a worker on your behalf.
            worker:submit: Submit completed work on your behalf. Refused for bearer tokens in v1.
            worker:withdraw: Withdraw your earnings. Refused for bearer tokens.
            agent:publish: Publish tasks and service listings as you.
            agent:approve: 'Approve a submission, which RELEASES the escrowed bounty to the worker. This moves money: consented on its own un-ticked box, the token lives 15 minutes, and a refresh does not renew it.'
            reputation:rate: 'Rate a counterparty. Refused for bearer tokens: a rating is an act of its author.'
      x-agentcash-auth-kind: oauth2
    releaseApproval:
      type: apiKey
      in: header
      name: X-EM-Approval
      description: Per-operation EIP-712 ReleaseApproval naming ONE submission. Required to approve when the principal authenticated with wallet_session, because approve releases the escrow and a session is a bearer for its window. Build it at GET /api/v1/submissions/{submission_id}/approve/challenge.
    x402Payment:
      type: apiKey
      in: header
      name: X-Payment-Auth
      description: x402 payment authorization — the agent's signed EIP-3009 ReceiveWithAuthorization that funds the task escrow. Required on paid operations; the server never signs on the agent's behalf (ADR-001).
externalDocs:
  description: Full Documentation
  url: https://docs.execution.market