rendry-io Rendering API

The Rendering API from rendry-io — 1 operation(s) for rendering.

Operations 1

POST /art/prepare Quote or prepare a preset's art, or read an art job #

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/rendry-io:rendry-io-rendering-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

rendry-io-rendering-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Rendry Rendering API
  version: 1.6.0
  description: 'Template-based image generation API. Design a template in the visual editor (or via POST /presets), then render on-brand images with one call. Every capability the MCP server exposes as a tool is reachable over REST as well — same implementation behind both, so the two never drift. For AI agents a remote MCP endpoint is available at /mcp (streamable HTTP) — see https://rendry.io/llms-full.txt. Every refusal, on every door, is one JSON object {error: machine code, message: sentence, …fields} with the HTTP status of its class — see the Refusal schema; an MCP tool error carries the same object as its text.


    Authentication: four bearer credentials open the render and template doors — a persisted live or test API key (sk_live_… / sk_test_…), the browser session of the signed-in owner (the JWT POST /auth/login returns) a connector token (the JWT the OAuth flow issues to an MCP client), and an ephemeral editor session (em_…). Browser/OAuth credentials may select a current team membership with X-Rendry-Account; API keys and embed sessions are bound to their persisted account and cannot switch accounts. GET /principal returns the resolved authority. Roles and scopes intersect; a removed member immediately loses access. Test mode is persisted on the credential: renders retain all admission limits, cost zero credits and carry a RENDRY TEST watermark; test credentials cannot publish public links. Operations that list the `session` scheme alone are the account cabinet: an API key is refused there with 401, a connector token with 403 `browser_session_required` (account deletion: `account_deletion_needs_session`). Operations with an empty `security` are public.


    Also served, not described operation by operation: GET /templates/{id}/preview.png and GET /template-assets/{name} (public; the gallery''s pictures), GET /assets/library (public; the built-in image stock), GET /plans, GET /billing/config and GET /version (public; prices and the running build), GET /openapi.json (public; this document), POST /feedback (public, rate-limited by IP) and POST /feedback/agent (render credentials), the OAuth 2.1 doors under /oauth (the three /.well-known discovery documents, /register, /authorize, /client-info, /token — public; POST /oauth/decision takes the owner''s session), the guest batch under /batch-tasks/guest (public, rate-limited by IP: POST /preview, POST, GET /{token}, GET /{token}/archive), the sign-in, sign-up, e-mail verification and password doors under /auth (public; POST /auth/verify/resend takes the owner''s session), the cabinet''s POST /user/password, POST /checkout, GET /billing/history, GET /billing/subscription, GET /photos/search and POST /photos/used (owner''s session only), the payment webhooks POST /billing/webhook and POST /billing/webhook/{provider} (signed by the provider), the /internal/* doors of the render nodes (internal token) and the /admin group (administrators, session only).'
  contact:
    url: https://rendry.io
servers:
- url: https://rendry.io/api/v1
  description: Production
security:
- apiKey: []
- session: []
- connector: []
- embed: []
tags:
- name: Rendering
paths:
  /art/prepare:
    post:
      operationId: prepareArt
      summary: Quote or prepare a preset's art, or read an art job
      description: Requires full scope; embed principals are refused. dry_run works with test keys, but a real test-key run makes no images and says test renders use placeholders. Real jobs run in the API, applying shared image limits, slots and server budget before charging each image through generate_asset's core. Poll job_id; failed images report refunds. An interrupted job says to call prepare_art again; completed art is reused free. Every render surface only reads cached art and refuses missing art before any render charge.
      tags:
      - Rendering
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PrepareArtRequest'
      responses:
        '200':
          description: Quote, admitted job, progress or free test-key response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PrepareArtReply'
        '400':
          description: Invalid arguments, prompt or row
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Refusal'
        '401':
          description: Authentication required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Refusal'
        '403':
          description: Full scope required, embed principal refused or asset slots full
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Refusal'
        '404':
          description: Preset, style or job not found for this account and subject
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Refusal'
        '429':
          description: Image daily or concurrent limit reached
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Refusal'
        '503':
          description: Feature disabled, provider budget exhausted or storage unavailable
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Refusal'
components:
  schemas:
    ArtTestPlaceholder:
      type: object
      properties:
        placeholder:
          type: boolean
        to_make:
          type: integer
          minimum: 0
        price_credits:
          type: number
          minimum: 0
          description: Credits from the shared per-image price; cached images cost nothing.
        message:
          type: string
        autofixed_fields:
          type: array
          items:
            type: string
        autofix_note:
          type: string
      required:
      - placeholder
      - to_make
      - price_credits
      - message
    ArtJobProgress:
      type: object
      properties:
        job_id:
          type: string
          format: uuid
        status:
          type: string
          enum:
          - running
          - done
          - failed
          - interrupted
        made:
          type: integer
          minimum: 0
        cached:
          type: integer
          minimum: 0
        failed:
          type: array
          items:
            type: object
            properties:
              prompt:
                type: string
              reason:
                type: string
              refunded:
                type: boolean
            required:
            - prompt
            - reason
            - refunded
        assets:
          type: array
          items:
            type: object
            properties:
              prompt:
                type: string
              url:
                type: string
              storage_key:
                type: string
            required:
            - prompt
            - url
            - storage_key
        credits_charged:
          type: number
          minimum: 0
          description: Credits from the shared per-image price; cached images cost nothing.
        message:
          type: string
        autofixed_fields:
          type: array
          items:
            type: string
        autofix_note:
          type: string
      required:
      - job_id
      - status
      - made
      - cached
      - failed
      - assets
      - credits_charged
    PrepareArtRowsRequest:
      type: object
      properties:
        preset_id:
          type: string
        rows:
          type: array
          maxItems: 10
          items:
            type: object
            properties:
              dynamic_data:
                type: object
                additionalProperties:
                  type: string
              filename:
                type: string
              rows:
                type: object
                additionalProperties:
                  type: array
                  items:
                    type: object
                    additionalProperties:
                      type: string
                description: This item's rows for its repeat groups and tables (rows_key)
            additionalProperties: false
          minItems: 1
        dry_run:
          type: boolean
          default: false
      required:
      - preset_id
      - rows
      additionalProperties: false
    VariableDiagnosticCode:
      type: string
      description: The stable codes of variable diagnostics (specs/007-nested-variables/contracts/language.md). A diagnostic names the variable, the code, a reason sub-code, the referenced name, a cycle path and a code-point span in the source — never a source string, a supplied value or a result. A schema problem refuses the save (invalid_name, invalid_mode, reserved_name, unsupported_row_scope, source_limit) and nothing is written; a definition that does not resolve from the saved values is saved and named in the save's warnings; at render every unresolvable definition refuses the request before any charge (400, nothing rendered, nothing charged) with the same codes.
      enum:
      - invalid_name
      - invalid_mode
      - invalid_format
      - invalid_format_value
      - reserved_name
      - unsupported_row_scope
      - unsupported_reference_scope
      - template_syntax
      - formula_syntax
      - unknown_reference
      - cycle
      - nonnumeric_operand
      - division_by_zero
      - numeric_limit
      - source_limit
      - node_limit
      - depth_limit
      - output_limit
      - circular_layout_dependency
    ArtJobStarted:
      type: object
      properties:
        job_id:
          type: string
          format: uuid
        to_make:
          type: integer
          minimum: 0
        price_credits:
          type: number
          minimum: 0
          description: Credits from the shared per-image price; cached images cost nothing.
        autofixed_fields:
          type: array
          items:
            type: string
        autofix_note:
          type: string
      required:
      - job_id
      - to_make
      - price_credits
    ArtQuote:
      type: object
      properties:
        distinct:
          type: integer
          minimum: 0
        existing:
          type: integer
          minimum: 0
        to_make:
          type: integer
          minimum: 0
        price_credits:
          type: number
          minimum: 0
          description: Credits from the shared per-image price; cached images cost nothing.
        limit_check:
          type: object
          properties:
            fits:
              type: boolean
            reason:
              type: string
          required:
          - fits
        prompts:
          type: array
          items:
            $ref: '#/components/schemas/ArtPromptQuote'
        autofixed_fields:
          type: array
          items:
            type: string
        autofix_note:
          type: string
      required:
      - distinct
      - existing
      - to_make
      - price_credits
      - limit_check
      - prompts
    ArtPromptQuote:
      type: object
      properties:
        prompt:
          type: string
        rows:
          type: array
          items:
            type: integer
            minimum: 0
        status:
          type: string
          enum:
          - existing
          - to_make
      required:
      - prompt
      - rows
      - status
    PrepareArtJobRequest:
      type: object
      properties:
        job_id:
          type: string
          format: uuid
      required:
      - job_id
      additionalProperties: false
    PrepareArtReply:
      oneOf:
      - $ref: '#/components/schemas/ArtQuote'
      - $ref: '#/components/schemas/ArtJobStarted'
      - $ref: '#/components/schemas/ArtJobProgress'
      - $ref: '#/components/schemas/ArtTestPlaceholder'
    PrepareArtRequest:
      type: object
      properties:
        preset_id:
          type: string
        rows:
          type: array
          maxItems: 10
          items:
            type: object
            properties:
              dynamic_data:
                type: object
                additionalProperties:
                  type: string
              filename:
                type: string
              rows:
                type: object
                additionalProperties:
                  type: array
                  items:
                    type: object
                    additionalProperties:
                      type: string
                description: This item's rows for its repeat groups and tables (rows_key)
            additionalProperties: false
          minItems: 1
        dry_run:
          type: boolean
          default: false
        job_id:
          type: string
          format: uuid
      additionalProperties: false
      oneOf:
      - $ref: '#/components/schemas/PrepareArtRowsRequest'
      - $ref: '#/components/schemas/PrepareArtJobRequest'
      description: Rows are the same objects as render_batch items. Send preset_id and rows to quote or start; job_id alone reads durable progress. Row indexes start at zero. Dry runs create no image/job rows, charge nothing and call no provider.
    VariableDiagnostic:
      type: object
      description: One reason a variable does not resolve (spec 007). Names, codes, positions — never a source string, a supplied value or a resolved value.
      required:
      - code
      - severity
      properties:
        code:
          $ref: '#/components/schemas/VariableDiagnosticCode'
        severity:
          type: string
          enum:
          - error
          - warning
        variable:
          type: string
          description: The definition or supplied input the problem belongs to; empty for a context-wide limit.
        reference:
          type: string
          description: The referenced name (unknown_reference, nonnumeric_operand).
        path:
          type: array
          items:
            type: string
          description: A cycle, its first name repeated at the end.
        reason:
          type: string
          description: 'A stable sub-code: which syntax rule or which limit.'
        span:
          type: object
          description: Half-open range of Unicode code points in the definition's source.
          properties:
            start:
              type: integer
            end:
              type: integer
    Refusal:
      type: object
      description: 'Every refusal of every door (status 400 and above), on REST and as the JSON text of an MCP tool error. `error` is a stable machine code to branch on; `message` is an English sentence for the log or the agent. A door that names its condition uses its own code (preset_not_found, unknown_field, variables_unresolved, insufficient_credits, api_key_scope_insufficient, …) and adds its fields beside the two; any other refusal carries the code of its HTTP status class: 400 invalid_input (invalid_request when the body is not the JSON the door reads), 401 unauthorized / invalid_token / invalid_api_key, 403 forbidden, 404 not_found, 405 method_not_allowed (with `allow`), 408/504 timeout, 409 conflict, 413 request_too_large (with `limit_bytes`), 422 unprocessable, 429 rate_limit_exceeded, 500 internal_error, 502/503 service_unavailable. A path that does not exist answers 404 not_found and a wrong method 405 before any credential is read. The message never carries our infrastructure''s text (hosts, drivers, Go type names).'
      required:
      - error
      - message
      properties:
        error:
          type: string
          description: Machine code, snake_case.
        message:
          type: string
          description: What was refused and what to do, in English.
        fields:
          type: array
          description: 'unknown_field: each key the door does not read, with the nearest known key. Nothing was run or charged. A near miss (a typo of one or two letters, a known alias) is not refused: it is renamed and reported in the reply: `autofixes` on /render/sync, /render/async, /batch-tasks, /assets/import and /user/api-keys; `autofixed_fields` on the doors that run an MCP tool (/render/batch, /render/preview, PATCH /presets/{id}, components, theme, clone, palette).'
          items:
            type: object
            properties:
              field:
                type: string
                description: 'The key as sent, with its path: `items[0].filenme`.'
              did_you_mean:
                type: string
        diagnostics:
          type: array
          description: 'variables_unresolved: why the template''s variables do not resolve for this call. Never a source, a supplied value or a result. Absent on the public /u/ link, whose visitor is not the template''s author.'
          items:
            $ref: '#/components/schemas/VariableDiagnostic'
        prompt:
          type: string
          description: 'art_missing: the resolved art description.'
        prepare_art:
          $ref: '#/components/schemas/PrepareArtRequest'
        style_id:
          type: string
          description: An unavailable or unowned art style.
        generate_asset:
          type: object
          description: Exact cache-sharing repair for inline layouts, drafts, document masters and document-specific variable or page facts. Generate the supplied resolved prompt, then retry the render.
          properties:
            style_id:
              type: string
            prompt:
              type: string
            aspect:
              type: string
      additionalProperties: true
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      description: 'API key sk_live_... or sk_test_... — create at Settings → API Keys. Every key has a scope (read, render or full — see the APIKey schema); a call the scope does not cover answers 403 with `error` = `api_key_scope_insufficient`, the refused `tool`, the key''s `scope`, and a `message` naming what the key can call. A key limited to a list of presets answers a preset outside it with 403 `api_key_preset_not_allowed` and the refused `preset_id`; such a key renders and edits only its listed presets, and an inline design (canvas + layers, a document page or master of its own), a draft or a new template is refused with 403 `api_key_limited_to_presets` and a `reason` (inline_design, draft, create_template, inline_page). RESERVED: no door issues a key limited to presets yet — POST /user/api-keys hands out keys for the whole account — so `api_key_preset_not_allowed` and `api_key_limited_to_presets` are documented for clients built ahead of that door and are not answered by any key issued today.'
    session:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: 'The browser session of the signed-in owner: the JWT POST /auth/login (or the SSO door) returns, sent as `Authorization: Bearer <jwt>`. Opens every render and template door and, alone, the account cabinet (API keys, account deletion, password, billing).'
    connector:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: 'The token the OAuth 2.1 flow under /oauth issues to an MCP client (claude.ai connectors): the same JWT shape as a session, tagged as issued to a connector. Opens the render and template doors and /mcp; every cabinet door refuses it with 403 `browser_session_required`, account deletion with 403 `account_deletion_needs_session`.'
    embed:
      type: http
      scheme: bearer
      description: Ephemeral em_... token redeemed by the origin-restricted embedded editor. Its account, trusted subject, role and live/test mode are persisted server-side. It cannot access account administration, billing, account-wide batch services or public links. Never persist or put it in a URL.
x-rendry-service-policy:
  rates:
    rest_render:
      requests: 10
      window_seconds: 1
      burst: 10
      scope: account
      consistency: api_process
    mcp_request:
      requests: 10
      window_seconds: 1
      burst: 10
      scope: account
      consistency: api_process
    ui_request:
      requests: 10
      window_seconds: 1
      burst: 10
      scope: account
      consistency: api_process
    public_link:
      requests: 60
      window_seconds: 60
      burst: 60
      scope: ip
      consistency: api_process
    embed_frame:
      requests: 10
      window_seconds: 60
      burst: 10
      scope: ip
      consistency: api_process
    embed_redeem:
      requests: 10
      window_seconds: 60
      burst: 10
      scope: ip
      consistency: api_process
  sync_concurrency:
    account: 4
    subject: 2
    consistency: api_process
    scope: synchronous_render
  document_queue:
    pending_per_account: 4
    long_pending_per_account: 1
    long_above_pages: 20
    consistency: postgres_transaction
    scope: account; queued and processing documents
  retention:
    authenticated_days: 365
    guest_hours: 72
    url_cache_days: 30
    starts_at: 'authenticated: completion; guest: batch creation'
  end_user:
    header: X-End-User
    max_bytes: 64
    pattern: ^[A-Za-z0-9_.:@-]{1,64}$
    authority: analytics only; trusted embedded subject takes precedence
  notes:
  - REST, MCP and UI request buckets are separate; each account bucket is shared by members, keys and embedded subjects
  - API keys bypass only the UI bucket; authenticated embedded sessions use it
  - Sync concurrency is per API process; queued document admission is separately reserved in PostgreSQL
  - Retention is the source policy; deployment of storage lifecycle rules requires a separate operator action