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

> Start an off-session charge of the account's saved card to buy AI Gateway credits, then poll the purchase for its terminal outcome.

# Start a credit purchase



## OpenAPI

````yaml openapi/ai-gateway.yaml POST /credits/purchases
openapi: 3.0.3
info:
  title: AI Gateway APIs
  version: 0.1.0
  description: |
    Control-plane HTTP APIs served by the ai-gateway-control service.
servers:
  - url: https://api.ngrok.ai
security:
  - bearerAuth: []
tags:
  - name: AI Gateway Access Key Configurations
    description: Manage reusable access key configurations (scope and routing rules).
  - name: AI Gateway Access Keys
    description: Manage ngrok-managed access keys associated with AI Gateway endpoints.
  - name: AI Gateway Configuration
    description: >-
      Manage per-account AI Gateway configuration (timeouts, token caps,
      metadata).
  - name: AI Gateway API Keys
    description: Manage customer-facing AI Gateway API Keys.
  - name: AI Gateway Credits
    description: >-
      Purchase AI Gateway credits, via Stripe Checkout or a charge of the saved
      card, and read purchase/transaction history.
  - name: AI Gateway Providers
    description: Manage AI Gateway providers and the models they expose.
  - name: AI Gateway Custom Providers
    description: Manage custom AI Gateway providers and the models they expose.
  - name: AI Gateway Models
    description: >-
      Read-only listing of AI Gateway models available to the authenticated
      account.
  - name: AI Gateway Provider Keys
    description: Manage provider keys attached to AI Gateway managed access keys.
  - name: AI Gateway Usage
    description: >-
      Read-only AI Gateway usage events and aggregated usage overview for the
      authenticated account.
paths:
  /credits/purchases:
    post:
      tags:
        - AI Gateway Credits
      summary: Start a credit purchase
      description: >
        Start a charge using the account's saved card. A `200` response means
        the

        purchase has started, not that credits have been granted. Poll the GET

        endpoint until the purchase reaches a terminal state. Do not retry a

        `pending` purchase, since the charge may still be processing.


        The account must be provisioned for credit purchases and have a default

        payment method. If the account is not provisioned, use the checkout

        session endpoint instead. Cards cannot be added through this API and
        must

        first be saved in the ngrok dashboard.


        Send an `Idempotency-Key` with every purchase to prevent duplicate
        charges.

        Use a new key for each purchase attempt, including when retrying a
        declined

        purchase. Reusing a key returns the existing purchase instead of
        starting

        another charge.


        Idempotency keys:

        - Are limited to 255 characters.

        - Ignore leading and trailing whitespace.

        - Cannot be reused with a different `amount`. This returns
          `409 idempotency_key_reuse`.
        - Can be safely used across concurrent requests, which will all return
        the
          same purchase.

        If another purchase for the account is still unresolved, the request

        returns `409 purchase_in_progress`. Poll the returned

        `details.purchase_id` instead of retrying.


        Common errors include:

        - `400 metronome_not_provisioned`: Use the checkout session endpoint.

        - `400 no_default_payment_method`: Add a default payment method in the
          ngrok dashboard.
        - `400 invalid_idempotency_key`: The idempotency key is longer than 255
          characters.
        - `409 idempotency_key_reuse`: The key was already used with a different
          amount.
        - `409 purchase_in_progress`: Another purchase is still unresolved.
      operationId: CreateCreditPurchase
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreditPurchaseCreate'
      responses:
        '200':
          description: The purchase attempt that was started.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreditPurchase'
        default:
          $ref: '#/components/responses/Error'
components:
  parameters:
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: false
      description: |
        Optional key that makes retries safe. Reusing the same key returns the
        existing purchase instead of starting a second charge.

        Keys are scoped to the account and this operation, can be up to 255
        characters, and should be treated as permanently used. If the header is
        missing or empty, replay protection is disabled.
      schema:
        type: string
  schemas:
    CreditPurchaseCreate:
      type: object
      additionalProperties: false
      required:
        - amount
      properties:
        amount:
          type: integer
          format: int64
          minimum: 1
          maximum: 50000
          description: >-
            Amount in cents to purchase. Must be a positive integer, and cannot
            exceed the credit balance cap.
    CreditPurchase:
      type: object
      additionalProperties: false
      required:
        - id
        - status
        - amountCents
        - currency
        - createdAt
        - expiresAt
      properties:
        id:
          type: string
          description: Unique identifier for this credit purchase attempt.
        status:
          type: string
          enum:
            - pending
            - actionRequired
            - succeeded
            - failed
          description: >
            Current state of the purchase. Poll GET until it reaches a terminal

            state (succeeded or failed).


            An asynchronous webhook records `succeeded` and `actionRequired`,
            and

            a periodic sweep backstops a lost webhook. A purchase can therefore

            stay `pending` until the next sweep runs, after the charge itself

            settles.
        amountCents:
          type: integer
          format: int64
          description: Amount purchased, in cents.
        currency:
          type: string
          description: ISO 4217 currency code, lowercase.
        createdAt:
          type: string
          format: date-time
          description: When the purchase attempt was started.
        expiresAt:
          type: string
          format: date-time
          description: When the purchased credits stop being usable.
        failureCode:
          type: string
          nullable: true
          description: |
            Machine-readable decline reason. Set when status is failed, and also
            set to `ambiguous_upstream` while status is pending if a prior
            attempt's outcome could not be determined.
        failureMessage:
          type: string
          nullable: true
          description: Human-readable decline detail, set only when status is failed.
    Error:
      type: object
      additionalProperties: false
      required:
        - statusCode
        - msg
        - details
      properties:
        errorCode:
          type: string
          description: Stable ngrok error code when available.
        statusCode:
          type: integer
          format: int32
          description: HTTP status code for this error.
        msg:
          type: string
          description: Human-readable error message.
        details:
          type: object
          description: Structured error details.
          additionalProperties:
            type: string
  responses:
    Error:
      description: API error response.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer

````