> ## Documentation Index
> Fetch the complete documentation index at: https://docs.deapi.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Update Key

> Switches an API-role key on or off, changes its expiry date, spend limit and reset window, and sets the addresses it may be used from. Needs an ADMIN key. The role cannot be changed; ADMIN keys are changed in the Dashboard only. Making a key active again counts toward the limit of active keys.

<Note>
  Requires an **ADMIN** key. An API key gets `403` with `code: insufficient_permissions` — see [API Keys](/api-keys).
</Note>

Disable or re-enable an API key, or change its expiration date, spend limit, reset window or IP allowlist. Send only the fields you want to change. The role cannot be changed, and ADMIN keys can be changed only in the Dashboard.

Changes apply from the next request. Changing the spend limit does not reset the counter; changing the reset window does.


## OpenAPI

````yaml openapi-v2.json PATCH /api/v2/keys/{id}
openapi: 3.1.0
info:
  title: deAPI REST API
  description: >-
    Decentralized AI inference API for image generation, video processing, audio
    transcription, and more.


    ## Rate limits


    Two windows can apply to a request: a per-minute one (RPM) and a per-day one
    (RPD). Every

    throttled response — success or 429 — carries the `X-RateLimit-*` headers,
    so you can pace

    traffic without waiting to be rejected. Each header documents itself: see
    `components/headers`,

    or the headers listed on any response. What follows is only what a header
    cannot say about

    itself.


    Windows open on your first request into a bucket and run their full length
    from that second —

    never to a calendar boundary, in any timezone. That is deliberate: a
    boundary every account

    shares is a boundary every account can double up on.


    **The headers describe the pool *this* request landed in, and
    `X-RateLimit-Source` is what

    identifies it — not `X-RateLimit-Limit` alone.** A per-model limit is keyed
    to the model you

    named, so a request that carried no recognised `model` — rejected at
    validation, an unknown

    slug, an empty body — was counted against your tier pool, and it is the tier
    pool the headers

    then describe. The two pools are fully independent: separate minute window,
    separate day,

    separate `X-RateLimit-Daily-Reset`. This is a consequence of rate limiting
    running *before*

    validation, which is what keeps malformed traffic from reaching the rest of
    the API

    uncounted. Compare headers only across responses carrying the same
    `X-RateLimit-Source`.


    **Buckets are shared in ways worth knowing.** API **v1 and v2 count against
    the same bucket**,

    so migrating grants no fresh allowance and mixed traffic behaves as one
    stream. All `*/price`

    and `*/price-calculation` endpoints share a single quote bucket, separate
    from generation.

    Prompt enhancement (`/v2/prompts/enhancements`) has its own bucket as well,
    so heavy prompt

    work no longer eats into your image throughput.


    **Counting is exact in sequence, best-effort in parallel.** Sent one after
    another, your

    requests are counted precisely: the one that crosses the limit is the one
    that gets 429. Sent

    in parallel, a few beyond the limit can slip through, because the counter is
    read and then

    incremented as two steps and requests already in flight are not yet visible
    to one another.

    The excess is bounded by how many of your own requests are in flight at
    once, and it only

    ever runs in your favour — you are never rejected while below your limit. So
    do not treat

    `X-RateLimit-Remaining` as a reservation: it is a snapshot, and a request
    you sent a

    millisecond ago may already have spent what it shows.


    Requests rejected before authentication (HTTP 401) never reach the limiter
    and carry no

    rate-limit headers at all.
  contact:
    name: deAPI Support
    url: https://deapi.ai
    email: support@deapi.ai
  version: 0.0.1
servers:
  - url: https://api.deapi.ai
    description: Production API Server base URL
security:
  - bearerAuth: []
tags:
  - name: Client API v2
    description: Current client endpoints (OpenAI-aligned noun-based paths)
paths:
  /api/v2/keys/{id}:
    patch:
      tags:
        - Client API v2
      summary: Change an API key
      description: >-
        Switches an API-role key on or off, changes its expiry date, spend limit
        and reset window, and sets the addresses it may be used from. Needs an
        ADMIN key. The role cannot be changed; ADMIN keys are changed in the
        Dashboard only. Making a key active again counts toward the limit of
        active keys.
      operationId: updateApiKey
      parameters:
        - $ref: '#/components/parameters/AcceptHeader'
        - name: id
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              properties:
                active:
                  description: '`false` disables the key, `true` enables it again.'
                  type: boolean
                  example: false
                expires_at:
                  description: >-
                    `null` removes the expiry date. A date must be in the future
                    and no later than 2038-01-19 03:14:07 UTC, the latest
                    instant this platform can store — a 422, not a silently
                    shortened key.
                  type:
                    - string
                    - 'null'
                  format: date-time
                  example: '2027-01-31T23:59:59Z'
                ip_whitelist:
                  $ref: '#/components/schemas/ApiKeyIpWhitelist'
                  description: >-
                    Replaces the whole list — entries are not merged with the
                    ones already there. `[]` clears it and the key works from
                    any address again; omitting the field leaves the list
                    untouched, and an explicit `null` is refused.
                limit:
                  $ref: '#/components/schemas/ApiKeySpendLimit'
                  description: >-
                    The new spend limit per window, in USD. `null` removes the
                    limit; omitting the field leaves both the limit and what has
                    been spent against it untouched. Changing the amount never
                    resets the counter: raising it from 50 to 100 on a key that
                    has already spent 50 leaves 50 of room, and lowering it
                    below what has been spent accepts nothing more until the
                    window resets.
                reset_interval:
                  description: >-
                    The new window. Changing it restarts the counter. Can be
                    sent on its own, but only for a key that already has a
                    limit; alongside `"limit": null` it is refused.
                  type: string
                  example: daily
                  enum:
                    - none
                    - daily
                    - weekly
                    - monthly
              type: object
      responses:
        '200':
          description: The key after the change.
          content:
            application/json:
              schema:
                properties:
                  data:
                    $ref: '#/components/schemas/ApiKeyResource'
                type: object
        '401':
          description: >-
            Missing, unknown, expired or deactivated key — `code` says which:
            `missing_key`, `invalid_key`, `key_expired` or `key_revoked`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/response_error_default'
        '403':
          $ref: '#/components/responses/InsufficientPermissions'
        '404':
          description: No such key on this account.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/response_error_default'
        '422':
          $ref: '#/components/responses/ApiKeyLimitReached'
        '429':
          $ref: '#/components/responses/RateLimitExceeded'
      security:
        - bearerAuth: []
components:
  parameters:
    AcceptHeader:
      name: Accept
      in: header
      required: true
      schema:
        type: string
        default: application/json
        enum:
          - application/json
  schemas:
    ApiKeyIpWhitelist:
      description: >-
        The addresses an API key may be used from. An empty list means any
        address, which is what a key carries until a list is set. Entries are
        single IPv4/IPv6 addresses or CIDR ranges of either family, and a key
        with a non-empty list is refused from anywhere else — including a call
        whose address cannot be established. Sending the field replaces the
        whole list; `[]` clears it. A JSON object is refused, as is an entry
        that could never gate anything: a `/0` range (say "any address" with an
        empty list instead) and an IPv4 address written in IPv6 notation such as
        `::ffff:192.0.2.1` (write `192.0.2.1`, the form a caller is matched
        against).
      type: array
      items:
        type: string
        example: 203.0.113.7
      example:
        - 203.0.113.7
        - 198.51.100.0/24
      maxItems: 20
    ApiKeySpendLimit:
      description: >-
        What this key may spend per window, in USD. Null means no limit, which
        is what every key carries until one is set. `0` is a real value and
        means the key accepts no paid work at all. A limit is a ceiling, not a
        reservation: it holds nothing against the account balance, and the
        limits of an account's keys may add up to far more than the account has.
        Sending `null` removes the limit; because nothing is counted for a key
        without one, removing a limit and setting it again inside the same
        window starts the counter from zero.
      type:
        - number
        - 'null'
      format: float
      example: 100
      maximum: 999999.999999
      minimum: 0
    ApiKeyResource:
      required:
        - id
        - name
        - preview
        - role
        - status
        - created_at
        - expires_at
        - last_used_at
        - ip_whitelist
        - ip_whitelist_count
        - limit
        - reset_interval
        - limit_used
        - limit_remaining
        - limit_resets_at
      properties:
        id:
          description: >-
            Key id. The secret is never returned here — only once, by `POST
            /api/v2/keys`.
          type: integer
          example: 42
        name:
          type: string
          example: Production backend
        preview:
          description: Key id and the last characters of the secret, for recognising a key.
          type: string
          example: 42|...f3a
        role:
          description: >-
            `api` — inference and the key's own data; `admin` — also account
            billing and key management.
          type: string
          example: api
          enum:
            - api
            - admin
        status:
          type: string
          example: active
          enum:
            - active
            - revoked
            - expired
          description: >-
            `revoked` — disabled in the Dashboard or with `PATCH
            /api/v2/keys/{id}` (`active: false`); `expired` — past `expires_at`.
        created_at:
          type: string
          format: date-time
          example: '2026-09-22T10:00:00+00:00'
        expires_at:
          description: Null when the key does not expire.
          type:
            - string
            - 'null'
          format: date-time
          example: null
        last_used_at:
          type:
            - string
            - 'null'
          format: date-time
          example: '2026-09-22T11:30:00+00:00'
        ip_whitelist:
          $ref: '#/components/schemas/ApiKeyIpWhitelist'
        ip_whitelist_count:
          description: >-
            How many entries the list holds — `0` means the key works from any
            address.
          type: integer
          example: 2
          minimum: 0
        limit:
          $ref: '#/components/schemas/ApiKeySpendLimit'
        reset_interval:
          description: >-
            How often the spend limit starts over. `none` while the key has no
            limit, and for a limit that never resets.
          type: string
          example: monthly
          enum:
            - none
            - daily
            - weekly
            - monthly
        limit_used:
          description: >-
            Spent against the limit in the window running now, in USD. Null when
            the key has no limit — nothing is counted for a key without one. Not
            the same figure as `GET /api/v2/keys/{id}/usage`, which sums what
            the key spent over the period you ask for: this counts only what
            went through the ceiling since the current window opened.
          type:
            - number
            - 'null'
          format: float
          example: 41.25
        limit_remaining:
          description: >-
            What is left of the limit in this window, in USD; null when there is
            no limit. Never negative — a cost settled after the work was
            admitted can put the counter over the ceiling, and the key then
            simply accepts nothing more until the window resets.
          type:
            - number
            - 'null'
          format: float
          example: 58.75
        limit_resets_at:
          description: >-
            When the counter next starts over. Null when the key has no limit,
            and null when it has one that never resets (`reset_interval: none`).
            Windows are anchored on the key's creation instant, not the
            calendar: a key created on the 15th at 13:42 UTC resets on the 15th
            at 13:42.
          type:
            - string
            - 'null'
          format: date-time
          example: '2026-10-22T10:00:00+00:00'
      type: object
    response_error_default:
      properties:
        data:
          description: Information from success endpoint
          type: object
        message:
          description: Error general message
          type: string
        errors:
          description: Information about errors
          type: array
          items: {}
        statusCode:
          description: Status code
          type: integer
        code:
          description: >-
            A stable, machine-readable reason, on the responses that publish
            one. Refused credentials (401): `missing_key` — no Bearer
            credentials arrived at all; `invalid_key` — a key was presented but
            is unknown, carries the wrong secret, or is malformed; `key_expired`
            — past its expiry date; `key_revoked` — deactivated. Refused
            requests: `insufficient_permissions` (403), `ip_not_allowed` (403),
            `active_key_limit_reached` (422), `insufficient_balance` (422),
            `key_limit_exceeded` (402), `rate_limited` (429). Absent wherever a
            response publishes no code, so treat an unknown value as the status
            code alone — the list grows.
          type: string
          enum:
            - missing_key
            - invalid_key
            - key_expired
            - key_revoked
            - insufficient_permissions
            - ip_not_allowed
            - active_key_limit_reached
            - insufficient_balance
            - key_limit_exceeded
            - rate_limited
      type: object
    response_error_rate_limit:
      description: Rate limit exceeded response
      properties:
        message:
          description: Error message
          type: string
          example: Too Many Attempts.
      type: object
  responses:
    InsufficientPermissions:
      description: >-
        The API key may not make this call. `insufficient_permissions` — its
        role does not cover this endpoint; account billing and key management
        need an ADMIN key, and the role is fixed when the key is created.
        `ip_not_allowed` — the key carries an IP whitelist and the call did not
        come from an address on it; nothing is created and nothing is charged,
        and the call does not spend the account's request allowance. Keep
        calling from a refused address and the 403 turns into a 429 with
        `X-RateLimit-Type: ip-not-allowed`, counted against that address alone.
      content:
        application/json:
          schema:
            properties:
              message:
                type: string
                example: This API key does not have permission to access this endpoint.
              code:
                type: string
                example: insufficient_permissions
                enum:
                  - insufficient_permissions
                  - ip_not_allowed
            type: object
    ApiKeyLimitReached:
      description: >-
        The account already has as many active API keys as it may. Disabled,
        expired and deleted keys do not count — disable or delete keys that are
        no longer used. This is the number of keys, not money: a key that has
        spent its own `limit` is refused with 402 `key_limit_exceeded`, never
        with this code.
      content:
        application/json:
          schema:
            properties:
              message:
                type: string
                example: >-
                  You have reached the limit of 100 active API keys — delete or
                  deactivate the ones you no longer use.
              code:
                type: string
                example: active_key_limit_reached
                enum:
                  - active_key_limit_reached
            type: object
    RateLimitExceeded:
      description: >-
        Rate limit exceeded. Check X-RateLimit-Type header to determine if
        minute (RPM) or daily (RPD) limit was hit.
      headers:
        X-RateLimit-Limit:
          $ref: '#/components/headers/X-RateLimit-Limit'
        X-RateLimit-Remaining:
          $ref: '#/components/headers/X-RateLimit-Remaining'
        X-RateLimit-Daily-Limit:
          $ref: '#/components/headers/X-RateLimit-Daily-Limit'
        X-RateLimit-Daily-Remaining:
          $ref: '#/components/headers/X-RateLimit-Daily-Remaining'
        X-RateLimit-Type:
          $ref: '#/components/headers/X-RateLimit-Type'
        Retry-After:
          $ref: '#/components/headers/Retry-After'
        X-RateLimit-Reset:
          $ref: '#/components/headers/X-RateLimit-Reset'
        X-RateLimit-Daily-Reset:
          $ref: '#/components/headers/X-RateLimit-Daily-Reset'
        X-RateLimit-Source:
          $ref: '#/components/headers/X-RateLimit-Source'
        X-RateLimit-Policy:
          $ref: '#/components/headers/X-RateLimit-Policy'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/response_error_rate_limit'
  headers:
    X-RateLimit-Limit:
      description: Maximum requests allowed per minute (RPM)
      schema:
        type: integer
        example: 3
    X-RateLimit-Remaining:
      description: Remaining requests in current minute window
      schema:
        type: integer
        example: 2
    X-RateLimit-Daily-Limit:
      description: Maximum requests allowed per day (RPD)
      schema:
        type: integer
        example: 100
    X-RateLimit-Daily-Remaining:
      description: Remaining requests in current day window
      schema:
        type: integer
        example: 95
    X-RateLimit-Type:
      description: >-
        Which limit rejected the request. Sent only on 429. Read it before
        anything else on the response: it decides what the other `X-RateLimit-*`
        headers are counting.


        `minute` — the per-request RPM window. `daily` — the per-request RPD
        window; the Daily-* pair is the one at 0.


        `key-creation` — the hourly cap on keys created over the API (`POST
        /api/v2/keys`), per account and shared by its ADMIN keys. The whole
        `X-RateLimit-*` set describes that bucket and there are no Daily-*
        headers.


        `ip-not-allowed` — too many calls from an address your key's IP
        whitelist refuses. Counted against that address, never against your
        account.
      schema:
        type: string
        example: minute
        enum:
          - minute
          - daily
          - key-creation
          - ip-not-allowed
    Retry-After:
      description: >-
        Seconds until the window that rejected you frees up (60 for minute, up
        to 86400 for daily). Counted from when that window opened, not to a
        calendar boundary. Sent only on 429.
      schema:
        type: integer
        example: 60
    X-RateLimit-Reset:
      description: >-
        Epoch second at which the minute (RPM) window refills. Fixed window —
        the value does not drift as you spend the quota. Describes the same
        window as X-RateLimit-Limit, including on a daily rejection.
      schema:
        type: integer
        example: 1755800460
    X-RateLimit-Daily-Reset:
      description: >-
        Epoch second at which the daily (RPD) window refills — 86400 s after the
        first request that opened this bucket's window, not a calendar midnight.
        Present only when a daily limit applies.
      schema:
        type: integer
        example: 1755846000
    X-RateLimit-Source:
      description: >-
        Where the limit came from, so you know what would change it:

        `tier` — your account tier's rate for this endpoint;

        `fallback` — no rate configured for this tier and endpoint, degraded
        default in force;

        `model` — a per-model override for the model in the request, unaffected
        by your tier

        (only when the request carried a recognised `model`, otherwise the tier
        pool applies);

        `static` — a flat limit outside the tier system, identical for every
        account.


        If you ever see `fallback`, tell us: it means no rate is configured for
        that tier and endpoint.
      schema:
        type: string
        example: tier
        enum:
          - tier
          - fallback
          - model
          - static
    X-RateLimit-Policy:
      description: >-
        Every window that applies, as `<limit>;w=<seconds>` elements. Always
        present on a throttled response, so a single element means there is no
        daily limit — do not infer that from the absence of the Daily-* headers.
        `300;w=60` is minute-only; `3;w=60, 100;w=86400` is both.
      schema:
        type: string
        example: 3;w=60, 100;w=86400
  securitySchemes:
    bearerAuth:
      type: http
      description: >-
        Sanctum personal access token, sent as `Authorization: Bearer <token>`.
        The token is opaque — it carries no claims and no embedded expiry, so do
        not attempt to decode it. Issue and revoke tokens from your account
        dashboard.
      scheme: bearer

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.