ImageStep Ops API

The catalogue of atomic operations: what `POST /api/v1/jobs` accepts in `op`, with each op's parameter contract, its price as data, an example request and the endpoint that runs it synchronously, if any. Read it instead of carrying a list of op names. AI ops charge credits per item; deterministic ops count against the plan's processing allowance; a sync op names the endpoint that answers it. **No credential needed** — an agent can read the catalogue before it has a key.

GitHub OpenAPI

Operations 2

GET /api/v1/ops List every atomic op with its parameter contract #
GET /api/v1/ops/{op} One op's contract #

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/imagestep-dev:imagestep-dev-ops-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

imagestep-dev-ops-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: ImageStep Ops API
  description: 'The image step for your automations. Store images as assets, run an op or a preset on them as a job — priced first with `?dryRun=true`, then read, waited on or delivered to a webhook — or transform one image synchronously while you wait. Send `Authorization: ApiKey `; the op catalogue (`/api/v1/ops`) needs no credential.


    **Idempotency:** Endpoints that accept an `Idempotency-Key` header support optional deduplication. Supply a unique key (e.g. a UUID) per logical request. Repeating the same key with the same body replays the stored response (`Idempotency-Replayed: true`) without re-running anything; repeating it with a different body is a 409 `idempotency_key_reuse`. Omitting the header processes the request normally. Keys are retained for 24 hours.


    **Errors** all share one shape: `{"error": {"code", "message", "retryable", "param", "details", "requestId"}}`. Branch on `code`, and let `retryable` — not the status code — decide whether to come back.


    **Rate limits** are published on every response as `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset` (seconds). A 429 adds `Retry-After`.


    **A paged list** takes `page` (from 0) and `perPage`, and every page answers `meta.nextCursor`; send it back as `cursor` to read on without counting.


    **Every response carries `X-Request-Id`** — yours if you sent one, ours otherwise — and a failure repeats it as `error.requestId`. It is what finds the request in our logs.


    The error-code table, idempotency, limits and pagination are at https://imagestep.dev/docs/errors; the webhook events at https://imagestep.dev/docs/webhooks; what may change inside v1, and the changelog, at https://imagestep.dev/docs/changelog.'
  contact:
    name: ImageStep Team
    url: https://imagestep.dev/support
  license:
    name: Proprietary
    url: https://imagestep.dev/terms
  version: v1
servers:
- url: https://api.imagestep.dev
  description: Production server
tags:
- name: Ops
  description: 'The catalogue of atomic operations: what `POST /api/v1/jobs` accepts in `op`, with each op''s parameter contract, its price as data, an example request and the endpoint that runs it synchronously, if any. Read it instead of carrying a list of op names. AI ops charge credits per item; deterministic ops count against the plan''s processing allowance; a sync op names the endpoint that answers it. **No credential needed** — an agent can read the catalogue before it has a key.'
paths:
  /api/v1/ops:
    get:
      tags:
      - Ops
      summary: List every atomic op with its parameter contract
      description: 'Every atomic op, with what a program needs to call it without a list of its own. Submit one with

        `POST /api/v1/jobs {"op": "", "assetIds": [...], "parameters": {...}}`, priced first with

        `?dryRun=true`. Chaining ops is a list of steps — inline as `steps` on `POST /api/v1/jobs`, or

        saved as a preset (`POST /api/v1/presets`). Answers without a credential.


        What each entry carries:

        - `params` — the parameter contract: name → type, bounds, default, description

        - `pricing` — the price as data: `basis` (`per_item` · `process_quota` · `free`); for an AI op, `defaultModel` is that model''s published price (the record `GET /api/pricing/image-models` publishes) with `markup` and `creditsPerUsd`; for a deterministic op, `processLimit` is the allowance per billing period by plan (-1 unlimited)

        - `example` — one complete, validated `POST /api/v1/jobs` body with a placeholder asset id: copy it, swap the id. Absent for a sync op, which is not a job

        - `modelCategory` — AI ops: the category a `model` must carry (`GET /api/v1/ai-models` → `categories`) to run the op

        - `typicalSeconds` — how long one item usually takes as a job on the default model: a measured hint for sizing `wait`, not a promise; absent where nobody has measured

        - `syncEndpoint` — the endpoint that runs the op while you wait; absent when there is none


        USE THIS WHEN:

        - Building a tool list or an operation dropdown

        - Checking a request''s parameters before submitting it'
      operationId: list_5
      responses:
        '200':
          description: OK
          headers:
            RateLimit-Limit:
              description: Requests allowed in the current window
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests left in the current window
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the window resets
              schema:
                type: integer
                format: int32
            X-Request-Id:
              description: This request's id — echoed from your own `X-Request-Id` when you send one. Identical to `error.requestId` on a failure; quote it when reporting one.
              schema:
                type: string
          content:
            '*/*':
              schema:
                $ref: '#/components/schemas/ApiResponseListOpDefinition'
        '429':
          description: Rate limited — `error.code` is `rate_limited` and `retryable` is true. `Retry-After` says how many seconds to wait.
          headers:
            Retry-After:
              description: Seconds to wait before retrying
              schema:
                type: integer
                format: int32
            RateLimit-Limit:
              description: Requests allowed in the current window
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests left in the current window
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the window resets
              schema:
                type: integer
                format: int32
            X-Request-Id:
              description: This request's id — echoed from your own `X-Request-Id` when you send one. Identical to `error.requestId` on a failure; quote it when reporting one.
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security: []
  /api/v1/ops/{op}:
    get:
      tags:
      - Ops
      summary: One op's contract
      description: 'The catalogue entry of one op, as `GET /api/v1/ops` lists it: its parameters, its price, an example

        request and its synchronous endpoint. Answers without a credential.'
      operationId: get_3
      parameters:
      - name: op
        in: path
        description: The op's name, as `op` in the catalogue
        required: true
        schema:
          type: string
        example: remove_bg
      responses:
        '200':
          description: The op's entry
          headers:
            RateLimit-Limit:
              description: Requests allowed in the current window
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests left in the current window
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the window resets
              schema:
                type: integer
                format: int32
            X-Request-Id:
              description: This request's id — echoed from your own `X-Request-Id` when you send one. Identical to `error.requestId` on a failure; quote it when reporting one.
              schema:
                type: string
          content:
            '*/*':
              schema:
                $ref: '#/components/schemas/ApiResponseOpDefinition'
        '404':
          description: '`not_found` — no such op; the message lists the ones there are'
          headers:
            RateLimit-Limit:
              description: Requests allowed in the current window
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests left in the current window
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the window resets
              schema:
                type: integer
                format: int32
            X-Request-Id:
              description: This request's id — echoed from your own `X-Request-Id` when you send one. Identical to `error.requestId` on a failure; quote it when reporting one.
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          description: Rate limited — `error.code` is `rate_limited` and `retryable` is true. `Retry-After` says how many seconds to wait.
          headers:
            Retry-After:
              description: Seconds to wait before retrying
              schema:
                type: integer
                format: int32
            RateLimit-Limit:
              description: Requests allowed in the current window
              schema:
                type: integer
                format: int32
            RateLimit-Remaining:
              description: Requests left in the current window
              schema:
                type: integer
                format: int32
            RateLimit-Reset:
              description: Seconds until the window resets
              schema:
                type: integer
                format: int32
            X-Request-Id:
              description: This request's id — echoed from your own `X-Request-Id` when you send one. Identical to `error.requestId` on a failure; quote it when reporting one.
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security: []
components:
  schemas:
    ApiError:
      type: object
      description: Structured error. Present on every 4xx/5xx response, absent on success.
      properties:
        code:
          type: string
          description: Machine-readable error code from a closed set
          example: invalid_param
        message:
          type: string
          description: Human-readable explanation. Never parse this — parse `code`.
          example: 'format must be one of: jpeg, png, webp'
        retryable:
          type: boolean
          description: Whether repeating the same request unchanged could succeed. The whole reason this field exists is that an agent cannot infer it from the status code.
          example: false
        param:
          type: string
          description: Which request parameter the error is about, when it is about one
          example: format
        details:
          type: object
          additionalProperties: {}
          description: Extra machine-readable context, e.g. per-field validation messages
        requestId:
          type: string
          description: 'The id of this request, identical to the `X-Request-Id` response header. Quote it when reporting a failure: it is what finds the request in our logs.'
          example: 9f0c1c2e-6f2a-4f6b-9d3e-0a1b2c3d4e5f
      required:
      - retryable
    OpPricing:
      type: object
      description: 'An op''s price as data: the basis, and the numbers behind it read from the catalogues that own them'
      properties:
        basis:
          type: string
          description: '`per_item`: credits per output item at the model''s USD price · `process_quota`: counted against the plan''s processing allowance, and paid from the balance per run past it (`overageCredits`) · `free`'
          enum:
          - per_item
          - process_quota
          - free
        summary:
          type: string
          description: The same, in one sentence
        defaultModel:
          $ref: '#/components/schemas/ImageModelPrice'
          description: 'AI ops: the default model''s published price, as `GET /api/pricing/image-models` lists it'
        markup:
          type: number
          format: double
          description: 'AI ops: `price = providerPrice × (1 + markup)`'
        creditsPerUsd:
          type: integer
          format: int64
          description: 'AI ops: credits per US dollar'
        processLimit:
          type: object
          additionalProperties:
            type: integer
            format: int32
          description: 'Deterministic ops: items per billing period, by plan; -1 is unlimited'
        overageCredits:
          type: object
          additionalProperties:
            type: integer
            format: int64
          description: 'Deterministic ops: credits per run past `processLimit`, paid from the balance — by plan, for the plans that have a limit'
        exactPrice:
          type: string
          description: How to learn the exact price of one request before spending it
    OpDefinition:
      type: object
      description: 'One atomic op: what it does, how to call it, what it costs and whether it can run while you wait'
      properties:
        op:
          type: string
          description: The op's name — what `op` takes on a job, a preset step or a synchronous call
          example: remove_bg
        kind:
          type: string
          description: '`ai` runs a model and is charged credits per item; `deterministic` is an image pipeline, counted against the processing allowance; `sync` is answered by an endpoint, never a job'
          enum:
          - ai
          - deterministic
          - sync
        produces:
          type: string
          description: 'What a step of this op hands to the next: an image, or a JSON answer — which only a last step can produce'
          enum:
          - image
          - json
        description:
          type: string
          description: What the op does, in one sentence
        jobType:
          type: string
          description: The job type the op runs as; absent for a sync op
        endpoint:
          type: string
          description: 'A sync op: the endpoint that answers it instead of a job'
        requiresAssets:
          type: boolean
          description: Whether a job of this op needs `assetIds`
        requiresPrompt:
          type: boolean
          description: Whether a job of this op needs a `prompt`
        defaultModel:
          type: string
          description: 'AI ops: the model a request that names none runs on; its price is `pricing.defaultModel`'
        defaultPrompt:
          type: string
          description: '`analyze` only: what it asks when neither the request nor its preset gives a prompt'
        defaultSchema:
          type: object
          additionalProperties: {}
          description: '`analyze` only: the answer''s JSON Schema when neither the request nor its preset gives `parameters.schema`'
        params:
          type: object
          additionalProperties:
            type: object
            additionalProperties: {}
          description: 'The parameter contract: name → `{type, enum?, min?, max?, required?, default?, description}` — `enum`, `min` / `max` and `required` are what the op enforces. A deterministic op refuses any other parameter with `400 invalid_param`'
        pricing:
          $ref: '#/components/schemas/OpPricing'
          description: How the op is priced, as data; the exact price of one request is the dry run
        syncEndpoint:
          type: string
          description: 'The endpoint that runs the op while you wait — bytes in, bytes out, nothing stored — or absent when it has none. AI ops never do: a model call needs a job to own its retry and refund'
        maxInputEdge:
          type: integer
          format: int32
          description: 'AI ops: the longest edge, in pixels, an input image is scaled down to before the default model sees it; another model''s is its `maxInputEdge` in GET /api/v1/ai-models'
        modelCategory:
          type: string
          description: 'AI ops: the category a model must carry (GET /api/v1/ai-models → `categories`) to run this op; any other `model` is `400 invalid_param`'
        example:
          type: object
          additionalProperties: {}
          description: One complete `POST /api/v1/jobs` body that runs this op, with a placeholder asset id — it has passed the same validator a submit does. Absent for a sync op
        typicalSeconds:
          type: integer
          format: int32
          description: How long one item usually takes as a job, submit to terminal, on the default model — a measured median for sizing `wait`, not a promise. Absent where nobody has measured it, which never means fast
      required:
      - requiresAssets
      - requiresPrompt
    ApiResponseListOpDefinition:
      type: object
      description: Standard API response wrapper containing status, message, data and timestamp
      properties:
        success:
          type: boolean
          description: Indicates if the request was successful
          example: true
        message:
          type: string
          description: Human-readable message about the response
          example: Operation completed successfully
        data:
          type: array
          description: The response data payload
          items:
            $ref: '#/components/schemas/OpDefinition'
        timestamp:
          type: string
          format: date-time
          description: Timestamp when the response was generated
          example: '2024-01-15T10:30:45.123Z'
        error:
          $ref: '#/components/schemas/ApiError'
          description: Structured error; present exactly when the request failed
        meta:
          $ref: '#/components/schemas/PageMeta'
          description: Pagination metadata for list responses
      required:
      - data
      - success
    ErrorResponse:
      type: object
      description: 'The answer to every failed request: `error` says what went wrong and whether to retry, and nothing else rides beside it — no `data`, no `meta`.'
      properties:
        success:
          type: boolean
          description: Always `false` on a failure
        error:
          $ref: '#/components/schemas/ApiError'
        timestamp:
          type: string
          format: date-time
          description: When the response was generated
      required:
      - error
      - success
    ImageModelPrice:
      type: object
      description: 'A model''s published price: ours, after markup, beside the provider''s own list price'
      properties:
        id:
          type: string
          description: The model's id, as `model` names it
        name:
          type: string
          description: The model's name
        series:
          type: string
          description: The provider family
        description:
          type: string
          description: What the model does
        categories:
          type: array
          description: What the model is sold for — an op's `modelCategory` is one of these
          items:
            type: string
        priceFrom:
          type: string
          description: Our lowest price per image, in USD, as a decimal string
          example: '0.0024'
        priceRange:
          type: string
          description: Our price per image, or its range, written for a person
          example: $0.006 - $0.253
        providerPrice:
          type: string
          description: The provider's own list price per image, in USD, before our markup — the cheapest end when the price has a range
        providerPriceRange:
          type: string
          description: The provider's list price across the same span as `priceRange`, for a model whose cost depends on a parameter; absent when one number covers it
      required:
      - id
    PageMeta:
      type: object
      properties:
        total:
          type: integer
          format: int64
          description: 'Rows matching the filter. Page mode only: a cursor request counts nothing'
        page:
          type: integer
          format: int32
          description: The page served, from 0. Page mode only
        perPage:
          type: integer
          format: int32
          description: Rows per page actually used (out of range is clamped)
        hasMore:
          type: boolean
          description: Whether there is another page
        nextCursor:
          type:
          - string
          - 'null'
          description: Pass back as `cursor` for the rows after this page; null on the last page. Opaque — send it unchanged, with the same filters
    ApiResponseOpDefinition:
      type: object
      description: Standard API response wrapper containing status, message, data and timestamp
      properties:
        success:
          type: boolean
          description: Indicates if the request was successful
          example: true
        message:
          type: string
          description: Human-readable message about the response
          example: Operation completed successfully
        data:
          $ref: '#/components/schemas/OpDefinition'
          description: The response data payload
        timestamp:
          type: string
          format: date-time
          description: Timestamp when the response was generated
          example: '2024-01-15T10:30:45.123Z'
        error:
          $ref: '#/components/schemas/ApiError'
          description: Structured error; present exactly when the request failed
        meta:
          $ref: '#/components/schemas/PageMeta'
          description: Pagination metadata for list responses
      required:
      - data
      - success
  securitySchemes:
    apiKeyAuth:
      type: apiKey
      description: 'API Key authentication. Format: ''ApiKey <your-api-key>''. Note: Only allowlisted endpoints accept API key authentication.'
      name: Authorization
      in: header