looot Runs API

The Runs API from looot — 6 operation(s) for runs.

Operations 7

GET /v1/runs List runs -- bounded summaries (runId, endpointId, providerId, status… #
POST /v1/runs Create a run -- idempotencyKey replay returns the existing run (any status)… #
GET /v1/runs/{runId} Get a run -- on a failed run, error carries { code, providerStatus, message… #
POST /v1/runs/{runId}/cancel Cancel a run #
GET /v1/runs/{runId}/media/{mediaId} Download a stored audio, image, video or PDF result of a run (bytes with the… #
GET /v1/runs/{runId}/attempts Inspect durable attempts and receipts #
GET /v1/runs/{runId}/artifacts List tenant-scoped run artifact metadata #

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/looot:looot-runs-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

looot-runs-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: looot Runs API
  version: 0.1.0
  description: Discover, inspect, run, and pay for real (or fixture) provider operations through one bearer token.
servers:
- url: https://api.looot.ai
  description: Public API (default)
- url: https://coset-gateway.onrender.com
  description: Legacy host -- still live, for tokens issued before the public domain existed
- url: http://127.0.0.1:8787
  description: Local development
security:
- bearerAuth: []
tags:
- name: Runs
paths:
  /v1/runs:
    get:
      summary: List runs -- bounded summaries (runId, endpointId, providerId, status…
      responses:
        '200':
          description: Success
      tags:
      - Runs
      operationId: getV1Runs
      x-operation-id-source: derived
    post:
      summary: Create a run -- idempotencyKey replay returns the existing run (any status)…
      description: 'customer-test friction #4 (docs/product/reviews/2026-09-04-customer-test): dispatch is woken immediately for the run''s workspace rather than left for the next poll tick, and the run always returns immediately unless `wait` asks otherwise (either as this query parameter or as a body field of the same name -- the query parameter wins if both are given). `wait=true` (or a bare `?wait`) waits up to the default of 20 s; a number is seconds, clamped to [0, 60]. Returns the result inline, in the same run shape this endpoint already returns, once it reaches a terminal status within `wait` seconds. If it is still queued/running when the window ends, returns that queued/running run instead, exactly as with no `wait` at all -- poll it with GET /v1/runs/{runId} or runs_get. A 201 can carry status:"failed" (a pre-dispatch denial such as endpoint_not_found or a validation_error) -- check the run''s own `status` and `error` fields, never the HTTP status code alone, to know whether it actually ran.'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RunRequest'
      parameters:
      - name: wait
        in: query
        schema:
          oneOf:
          - type: boolean
          - type: number
            minimum: 0
            maximum: 60
        description: Seconds to wait for a terminal result inline (default 20 when true/bare, max 60). Omit entirely for the pre-existing immediate-return behavior.
      - name: Idempotency-Key
        in: header
        required: false
        schema:
          type: string
          minLength: 1
        description: Alternative to the request body's idempotencyKey field. Either satisfies the (still mandatory) requirement; if both are present, they must be equal or the request is a 400.
      responses:
        '201':
          description: Run created (or the existing run replayed, any status, with replayed:true). A 201 is not itself success -- a pre-dispatch denial (endpoint_not_found, validation_error) also answers 201 with status:"failed" and a populated error; read the body, not the status code.
        '402':
          description: Out of balance -- the run was blocked before dispatch, never billed
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: object
                    additionalProperties: false
                    required:
                    - code
                    - message
                    - requestId
                    properties:
                      code:
                        type: string
                        const: insufficient_balance
                      message:
                        type: string
                      requestId:
                        type: string
                  balanceMicros:
                    type: integer
                  estimatedCostMicros:
                    type: integer
                  topUpUrl:
                    type: string
                    nullable: true
                  topUp:
                    type: object
                    properties:
                      minimumUsd:
                        type: number
                      suggestedUsd:
                        type: number
                      checkoutUrl:
                        type: string
                        nullable: true
                      dashboardUrl:
                        type: string
                      message:
                        type: string
                      reason:
                        type: string
                        enum:
                        - billing_disabled
                        - payment_processor_not_configured
                        - operator_workspace
                        - read_only_token
                        - rate_limited
                        - checkout_failed
                        - stripe_timeout
                        - amount_out_of_range
                        - balance_low
                        - balance_sufficient
                    required:
                    - minimumUsd
                    - suggestedUsd
                    - checkoutUrl
                    - dashboardUrl
                    - message
                required:
                - error
                - balanceMicros
                - estimatedCostMicros
                - topUpUrl
                - topUp
        '409':
          description: Idempotency-key conflict -- a request already exists for this key that this one does not match
        '429':
          description: Rate limit exceeded (execute class, too_many_inflight_runs) -- see Retry-After and X-RateLimit-* response headers
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: object
                    additionalProperties: false
                    required:
                    - code
                    - message
                    - requestId
                    properties:
                      code:
                        type: string
                        const: too_many_inflight_runs
                      message:
                        type: string
                      requestId:
                        type: string
                  inflight:
                    type: integer
                  limit:
                    type: integer
                  retryAfterSeconds:
                    type: integer
                required:
                - error
                - inflight
                - limit
                - retryAfterSeconds
      tags:
      - Runs
      operationId: postV1Runs
      x-operation-id-source: derived
  /v1/runs/{runId}:
    get:
      summary: Get a run -- on a failed run, error carries { code, providerStatus, message…
      responses:
        '200':
          description: Success
      description: '2026-09-27 (additive): a completed run can carry an optional `normalized` object next to `result`: { job, endpointId, fields, missing, ambiguous, unmapped, providerValues, verdict, verdictReason, mapVerified }, with fixed field names per job and one email status vocabulary (valid, invalid, catch_all, risky, unknown). Present only when the gateway has it turned on and the answering endpoint has an output map; absent, never null, otherwise. `result` and `outcome` are unchanged.'
      tags:
      - Runs
      operationId: getV1RunsByRunId
      x-operation-id-source: derived
  /v1/runs/{runId}/cancel:
    post:
      summary: Cancel a run
      responses:
        '200':
          description: Success
      tags:
      - Runs
      operationId: postV1RunsByRunIdCancel
      x-operation-id-source: derived
  /v1/runs/{runId}/media/{mediaId}:
    get:
      summary: Download a stored audio, image, video or PDF result of a run (bytes with the…
      responses:
        '200':
          description: Success
      tags:
      - Runs
      operationId: getV1RunsByRunIdMediaByMediaId
      x-operation-id-source: derived
  /v1/runs/{runId}/attempts:
    get:
      summary: Inspect durable attempts and receipts
      responses:
        '200':
          description: Success
      tags:
      - Runs
      operationId: getV1RunsByRunIdAttempts
      x-operation-id-source: derived
  /v1/runs/{runId}/artifacts:
    get:
      summary: List tenant-scoped run artifact metadata
      responses:
        '200':
          description: Success
      tags:
      - Runs
      operationId: getV1RunsByRunIdArtifacts
      x-operation-id-source: derived
components:
  schemas:
    RunRequest:
      type: object
      additionalProperties: false
      required:
      - endpointId
      - input
      properties:
        endpointId:
          type: string
          minLength: 1
          description: The catalog endpoint id to run
        input:
          type: object
          description: Arbitrary key/value input, validated against the endpoint's own input schema
        idempotencyKey:
          type: string
          minLength: 1
          description: Required, unless supplied instead as the Idempotency-Key request header (either satisfies the requirement; supplying both requires them to match, or the request is a 400). A replay with the same key and the same body returns the original run (replayed:true); the same key with a different body is a 409. Never auto-generated by the gateway -- see the report's decision options for why.
        output:
          type: object
          description: Optional output selection/mapping pin; same shape as an inspected endpoint's outputMappingPin
        wait:
          oneOf:
          - type: boolean
          - type: number
            minimum: 0
            maximum: 60
          description: Optional alternative to the ?wait= query parameter (the query parameter wins if both are given)
        fallback:
          description: Optional. Let the run move to the next provider of the same job when one misses or fails, within ONE hold; only attempts that ran are charged. true takes every default. The run then carries `route` {servedBy, outcome, chargedUsd, capped, attempts[], skipped[], summary}.
          oneOf:
          - type: boolean
          - type: object
            additionalProperties: false
            properties:
              enabled:
                type: boolean
                description: false turns it off (the same as omitting fallback)
              maxAttempts:
                type: integer
                minimum: 1
                maximum: 10
                description: Dispatched attempts, default 3
              maxCostUsd:
                type: number
                exclusiveMinimum: 0
                maximum: 100
                description: The route's cap; default the sum of the first maxAttempts prices; can only lower it
              prefer:
                enum:
                - cheapest
                - reliable
                - fastest
                - balanced
                description: Order of the job's other providers, default balanced
              exclude:
                type: array
                maxItems: 50
                items:
                  type: string
                  minLength: 1
                  maxLength: 200
                description: Endpoint or provider ids never tried
              stopAtFirstMiss:
                type: boolean
                description: Stop at the first empty answer, default false
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer