> ## 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.

# Create Key

> Creates a key with the API role. Needs an ADMIN key; ADMIN keys can only be created in the Dashboard. **The secret is returned once, in this response.** Counts toward the account's limit of active keys and the hourly limit of keys created over the API (shared by all ADMIN keys of the account). An `ip_whitelist` given here applies from the key's first call.

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

Create a new **API** key, optionally with an expiration date, spend limit, reset window and IP allowlist. ADMIN keys can only be created in the Dashboard.

<Warning>
  The `secret` is returned **only once**, in the response to this call. Store it straight away — it cannot be read again. If it is lost, create a new key and delete the old one.
</Warning>

Keys created over the API count toward the account limit of [100 active keys](/api-keys#number-of-keys). Creating keys is also rate-limited per account: too many in an hour returns `429` with `X-RateLimit-Type: key-creation`.


## OpenAPI

````yaml openapi-v2.json POST /api/v2/keys
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:
    post:
      tags:
        - Client API v2
      summary: Create an API key
      description: >-
        Creates a key with the API role. Needs an ADMIN key; ADMIN keys can only
        be created in the Dashboard. **The secret is returned once, in this
        response.** Counts toward the account's limit of active keys and the
        hourly limit of keys created over the API (shared by all ADMIN keys of
        the account). An `ip_whitelist` given here applies from the key's first
        call.
      operationId: createApiKey
      parameters:
        - $ref: '#/components/parameters/AcceptHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              required:
                - name
              properties:
                name:
                  type: string
                  example: Customer 1234
                  maxLength: 255
                expires_at:
                  description: >-
                    Optional. Leave it out for a key that never expires. 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: '2026-12-31T23:59:59Z'
                role:
                  description: Only `api`. `admin` is refused with 403.
                  type: string
                  example: api
                  enum:
                    - api
                    - admin
                ip_whitelist:
                  $ref: '#/components/schemas/ApiKeyIpWhitelist'
                  description: >-
                    Optional. The only addresses the new key may be used from;
                    omitted or `[]` means any. Duplicates and surrounding
                    whitespace are removed, an explicit `null` is refused.
                limit:
                  $ref: '#/components/schemas/ApiKeySpendLimit'
                  description: >-
                    Optional. What this key may spend per window, in USD;
                    omitted or `null` means no limit. Work that would take the
                    key past it is refused with 402 `key_limit_exceeded`.
                reset_interval:
                  description: >-
                    How often that limit starts over; `none` means it never
                    does. Only accepted together with a non-null `limit`.
                    Windows are anchored on the key's creation instant, not the
                    calendar.
                  type: string
                  example: monthly
                  default: none
                  enum:
                    - none
                    - daily
                    - weekly
                    - monthly
              type: object
      responses:
        '201':
          description: The new key, with its secret.
          content:
            application/json:
              schema:
                properties:
                  data:
                    $ref: '#/components/schemas/CreatedApiKeyResource'
                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'
        '422':
          $ref: '#/components/responses/ApiKeyLimitReached'
        '429':
          $ref: '#/components/responses/ApiKeyCreationRateLimited'
      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
    CreatedApiKeyResource:
      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
        - secret
      properties:
        id:
          description: Key id.
          type: integer
          example: 43
        name:
          type: string
          example: Customer 1234
        preview:
          type: string
          example: 43|...9bc
        role:
          type: string
          example: api
          enum:
            - api
        status:
          type: string
          example: active
          enum:
            - active
        created_at:
          type: string
          format: date-time
          example: '2026-09-22T12:00:00+00:00'
        expires_at:
          type:
            - string
            - 'null'
          format: date-time
          example: null
        last_used_at:
          type:
            - string
            - 'null'
          format: date-time
          example: null
        ip_whitelist:
          $ref: '#/components/schemas/ApiKeyIpWhitelist'
        ip_whitelist_count:
          type: integer
          example: 2
          minimum: 0
        limit:
          $ref: '#/components/schemas/ApiKeySpendLimit'
        reset_interval:
          description: How often the spend limit starts over. `none` when no limit was set.
          type: string
          example: monthly
          enum:
            - none
            - daily
            - weekly
            - monthly
        limit_used:
          description: >-
            Always `0` on a key that was just created, and null when it was
            created without a limit.
          type:
            - number
            - 'null'
          format: float
          example: 0
        limit_remaining:
          description: >-
            The whole limit on a key that was just created; null when it has
            none.
          type:
            - number
            - 'null'
          format: float
          example: 100
        limit_resets_at:
          description: >-
            One window after the key was created. Null when there is no limit or
            it never resets.
          type:
            - string
            - 'null'
          format: date-time
          example: '2026-10-22T12:00:00+00:00'
        secret:
          description: >-
            The full key for the `Authorization: Bearer` header. Returned only
            in this response — store it now, it cannot be read again.
          type: string
          example: 43|kx8…
      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
  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
    ApiKeyCreationRateLimited:
      description: >-
        Too many keys created over the API in the last hour — the limit is per
        account, shared by all its ADMIN keys and separate from keys created in
        the Dashboard. Retry after `Retry-After` seconds. Also returned when the
        general request rate for this endpoint is exceeded; `X-RateLimit-Type`
        tells them apart — `key-creation` here, `minute` or `daily` there.
      headers:
        Retry-After:
          description: Seconds until another key can be created.
          schema:
            type: integer
            example: 1800
        X-RateLimit-Type:
          $ref: '#/components/headers/X-RateLimit-Type'
        X-RateLimit-Limit:
          $ref: '#/components/headers/X-RateLimit-Limit'
        X-RateLimit-Remaining:
          $ref: '#/components/headers/X-RateLimit-Remaining'
        X-RateLimit-Reset:
          $ref: '#/components/headers/X-RateLimit-Reset'
        X-RateLimit-Policy:
          $ref: '#/components/headers/X-RateLimit-Policy'
      content:
        application/json:
          schema:
            properties:
              message:
                type: string
                example: Too many API keys created recently.
              code:
                type: string
                example: rate_limited
                enum:
                  - rate_limited
              retry_after:
                type: integer
                example: 1800
            type: object
  headers:
    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
    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-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-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.