rendry-io User API

The User API from rendry-io — 5 operation(s) for user.

Operations 7

GET /user/limits Plan and quota usage #
GET /user/usage Plan, quota used and reset date #
GET /user/api-keys List this account's API keys #
POST /user/api-keys Issue an API key with a scope #
DELETE /user/api-keys/{id} Revoke an API key #
GET /user/account/deletion What deleting this account would cost #
POST /user/account/deletion Close this account and schedule its deletion #

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-user-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-user-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Rendry User 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: User
paths:
  /user/limits:
    get:
      summary: Plan and quota usage
      description: Current plan, credit balance, template and asset slots used vs limits. Works with an API key — agents check the balance here, because credits are what a render fails on.
      responses:
        '200':
          description: Usage
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserLimits'
        '401':
          description: Missing/invalid credentials
      operationId: getUserLimits
      parameters:
      - $ref: '#/components/parameters/AccountSelector'
      security:
      - apiKey: []
      - session: []
      - connector: []
      tags:
      - User
  /user/usage:
    get:
      summary: Plan, quota used and reset date
      responses:
        '200':
          description: Usage
        '401':
          description: Missing/invalid API key
      operationId: getUserUsage
      parameters:
      - $ref: '#/components/parameters/AccountSelector'
      security:
      - apiKey: []
      - session: []
      - connector: []
      tags:
      - User
  /user/api-keys:
    get:
      summary: List this account's API keys
      security:
      - session: []
      description: 'For the signed-in owner, in a browser session. An API key cannot list, issue or revoke keys: it is refused with 401. A connector (MCP/OAuth) token is refused on every account-management door with 403 `browser_session_required`: a connector does MCP work, it does not manage keys. Each key is listed with its scope; the key itself is shown only as its first 12 characters. The resolved account may be selected with X-Rendry-Account; only an owner or admin browser session may administer its keys. The mode and actor are reported in each reply.'
      responses:
        '200':
          description: Array of APIKey
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/APIKey'
        '401':
          description: Not signed in, or an API key was used
        '403':
          description: '`error` is `browser_session_required`: a connector (MCP/OAuth) token was used'
      parameters:
      - $ref: '#/components/parameters/EndUserAnalytics'
      - $ref: '#/components/parameters/AccountSelector'
      operationId: listApiKeys
      tags:
      - User
    post:
      summary: Issue an API key with a scope
      description: 'For the signed-in owner, in a browser session (an API key is refused with 401). A connector (MCP/OAuth) token is refused on every account-management door with 403 `browser_session_required`: a connector does MCP work, it does not manage keys. The response carries the whole key once; it is not stored and cannot be shown again. `scope` decides what the key may do (see the APIKey schema). A request that names no scope gets a `full` key, as every key did before scopes could be chosen; an unknown scope is refused and nothing is issued. The resolved account may be selected with X-Rendry-Account; only an owner or admin browser session may administer its keys. The mode and actor are reported in each reply.'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - name
              properties:
                name:
                  type: string
                  description: Seen only by the owner, to tell keys apart when revoking. Stored without leading and trailing whitespace; one of whitespace alone is refused.
                  maxLength: 255
                scope:
                  type: string
                  enum:
                  - read
                  - render
                  - full
                  default: full
                mode:
                  type: string
                  enum:
                  - live
                  - test
                  default: live
                  description: Immutable execution mode, persisted on the issued key. Test rendering is watermarked and does not debit credits.
                actor_id:
                  type: string
                  description: Current member who owns this credential; defaults to the issuing browser actor. Member removal invalidates their keys.
      responses:
        '201':
          description: Issued. An APIKey whose key_value is the whole key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/APIKey'
        '400':
          description: 'The body is not JSON, `error` is `api_key_name_required` (the name is empty or only whitespace), `error` is `api_key_name_too_long` (the name is longer than `limit` characters), or `error` is `invalid_api_key_scope`: the scope is not one of read, render, full (they ride in `allowed`); `unknown_field` for a key this door does not read (a near miss is renamed and reported in `autofixes`). Nothing was issued.'
        '401':
          description: Not signed in, or an API key was used
        '403':
          description: '`error` is `browser_session_required`: a connector (MCP/OAuth) token was used'
      security:
      - session: []
      parameters:
      - $ref: '#/components/parameters/EndUserAnalytics'
      - $ref: '#/components/parameters/AccountSelector'
      operationId: createApiKey
      tags:
      - User
  /user/api-keys/{id}:
    delete:
      summary: Revoke an API key
      security:
      - session: []
      description: 'For the signed-in owner, in a browser session. Requests with the key stop working at once. A connector (MCP/OAuth) token is refused on every account-management door with 403 `browser_session_required`: a connector does MCP work, it does not manage keys.'
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
      - $ref: '#/components/parameters/EndUserAnalytics'
      - $ref: '#/components/parameters/AccountSelector'
      responses:
        '200':
          description: Revoked
        '401':
          description: Not signed in, or an API key was used
        '403':
          description: '`error` is `browser_session_required`: a connector (MCP/OAuth) token was used'
        '404':
          description: '`error` is `api_key_not_found`: this account has no key with that id — it never existed, was revoked already, or belongs to another account. Nothing was changed.'
      operationId: deleteApiKey
      tags:
      - User
  /user/account/deletion:
    get:
      summary: What deleting this account would cost
      security:
      - session: []
      description: 'For the signed-in owner, in a browser. Answers which confirmation this account uses (`confirm_with`: `password` when the owner has ever set one, otherwise `email`), the e-mail on the account, the credit balance that will be forfeited, and the retention window in days. NOT AVAILABLE TO AGENTS: an API key or an MCP/OAuth connector token is refused with `account_deletion_needs_session`, and there is no MCP tool for this.'
      responses:
        '200':
          description: confirm_with, email, credits_forfeited, retention_days
        '401':
          description: Not signed in; `error` is `unauthorized`
        '403':
          description: '`error` is `account_deletion_needs_session`: the request came with an API key or a connector token. Only the owner''s browser session may do this.'
      parameters:
      - $ref: '#/components/parameters/EndUserAnalytics'
      - $ref: '#/components/parameters/AccountSelector'
      operationId: getAccountDeletion
      tags:
      - User
    post:
      summary: Close this account and schedule its deletion
      security:
      - session: []
      description: 'Closes the account at once: sign-in stops, every issued token stops, every API key is revoked, queued render jobs are failed and refunded, and the remaining credits are forfeited. The data itself is erased after the retention window (`retention_days`), and until then support can restore the account. Payment and credit-ledger records are kept as accounting records, anonymised. NOT AVAILABLE TO AGENTS — see the GET above.'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                password:
                  type: string
                  description: The current password. Required when GET answered confirm_with=password.
                email:
                  type: string
                  description: The account's own e-mail, typed back. Required when GET answered confirm_with=email (an account created through SSO has no password of its own).
      responses:
        '200':
          description: Closed. Returns closed_at, deletion_date, retention_days, credits_forfeited, keys_revoked.
        '400':
          description: The body is not JSON
        '401':
          description: Not signed in; `error` is `unauthorized`
        '403':
          description: '`error` is a machine code: `account_deletion_needs_session` (an API key or a connector token was used) or `account_deletion_not_confirmed` (the password or e-mail did not match — nothing was changed).'
        '429':
          description: More than 5 attempts a minute from one address
      parameters:
      - $ref: '#/components/parameters/EndUserAnalytics'
      - $ref: '#/components/parameters/AccountSelector'
      operationId: deleteAccount
      tags:
      - User
components:
  schemas:
    APIKey:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        key_value:
          type: string
          description: The whole key (sk_live_... or sk_test_...) in the create response, and ONLY there — it is not stored. The list shows the first 12 characters followed by ***.
        scope:
          type: string
          enum:
          - read
          - render
          - full
          description: 'What the key may do. read: list and read templates, presets, documents, usage, and price a batch (POST /batch-tasks/preview parses the table and quotes the run, rendering and charging nothing) — no rendering, no changes. render: everything read may, plus render_image, render_batch, render_document and preview_preset (they spend credits) — no template edits or deletions. full: everything, including creating, editing, sharing and deleting templates and files.'
        created_at:
          type: string
        mode:
          type: string
          enum:
          - live
          - test
        actor_id:
          type: string
        issued_by_actor_id:
          type: string
    UserLimits:
      type: object
      properties:
        plan:
          type: string
        email:
          type: string
        presets:
          type: object
          properties:
            used:
              type: integer
            limit:
              type: integer
        assets:
          type: object
          properties:
            used:
              type: integer
            limit:
              type: integer
        upgrade_url:
          type: string
          description: Legacy alias of packages_url.
        credits:
          type: object
          description: Credit balance — the only thing a render actually fails on.
          properties:
            balance:
              type: number
            spent_on_renders:
              type: number
            grant_withheld:
              type: boolean
              description: Starter credits are held until the email is confirmed.
        packages_url:
          type: string
          description: Where to buy credits.
        email_verified:
          type: boolean
  parameters:
    EndUserAnalytics:
      name: X-End-User
      in: header
      required: false
      description: Analytics correlation only; never authorizes files or accounts. One safe ASCII value up to 64 bytes. Invalid values return 400. Persisted embedded subject takes precedence. Allowed by CORS.
      schema:
        type: string
        minLength: 1
        maxLength: 64
        pattern: ^[A-Za-z0-9_.:@-]{1,64}$
    AccountSelector:
      name: X-Rendry-Account
      in: header
      schema:
        type: string
      description: Browser/OAuth current member account selector. API keys/embed credentials are bound to their persisted account and reject another account. Omitting this header selects the browser actor personal account.
  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