Prepaid credit bundles for reusable API keys, with card checkout and USDC (x402) purchase options. Keep the same key for top-ups; batch validation debits one credit per IBAN. See each operation for its access and payment requirements.
Each operation below carries the questions people ask an LLM about it and the instructions they give an agent to run it. Generated by API Evangelistoverlay
1 of 3 operations are conformant: apis.io called them with no credentials and the responses matched this contract. Checked 2026-11-12. how this works · status file
GET/v1/credits/balanceCheck the prepaid credit balance of a key · Read the remaining credits of the presented key#
Ask an LLM
“How many prepaid credits are left on my key?”
“Does my key use its allowance before its credits?”
Tell an agent
Show the remaining credits on my API key.
Get my credit balance and the top-up links for this key.
GET/v1/credits/bundlesList prepaid credit bundles and prices · List prepaid credit bundles (free)conformant#
Ask an LLM
“What prepaid credit bundles are available and what do they cost?”
“Do purchased credits ever expire?”
Tell an agent
List the prepaid credit bundles with prices.
Show the credit packs and the monthly subscription option.
POST/v1/credits/buy/{bundle}Buy a prepaid credit bundle with USDC · Buy a prepaid credit bundle (x402, USDC)#
Ask an LLM
“Can I pay with USDC on Base to add credits to the key I already have?”
“What happens if I buy a bundle without presenting an API key?”
Tell an agent
Buy the {bundle} credit bundle for my current key.
Purchase bundle {bundle} and attach the new key to {email}.
Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.
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.
openapi: 3.2.0
info:
title: IBANforge Credits API
version: 1.9.0
description: IBANforge checks the bank behind an IBAN before you pay.
contact:
name: IBANforge support
url: https://github.com/cammac-creator/ibanforge/issues
email: support@ibanforge.com
servers:
- url: https://api.ibanforge.com
description: Production
- url: http://localhost:3000
description: Local development
tags:
- name: Credits
description: "Prepaid credit bundles for reusable API keys, with card checkout and USDC (x402) purchase options. Keep the same key for top-ups; batch validation debits one credit per IBAN. See each operation for its access and payment requirements."
paths:
/v1/credits/balance:
get:
operationId: getCreditBalance
summary: Read the remaining credits of the presented key
description: 'For a key with prepaid credits: credits_remaining, credits_total (everything ever bought on the key, recharges included), credits_used and the top-up endpoints. For a key without credits the answer is type: "subscription" with a pointer to GET /v1/keys/usage. On every key, `allowance` gives the allowance of the key (null on a key born of a purchase, which has none), `billing_order` is "allowance_then_credits" on a key that holds both, and `topup` carries the card links that recharge THIS key (and, on a key without a subscription, `topup.pro`: the Pro link that puts the subscription on it). When the credits of a key born of a purchase run out, billed routes answer 402 with cause.reason "credits_exhausted", the same links, and X-Credits-Topup-Url (the 1,000-credit one). Authentication is the key itself, in any of the three places every billed route accepts: Authorization: Bearer, X-API-Key, or ?api_key=.'
tags:
- Credits
security:
- apiKey: []
responses:
'200':
description: type ("credit_bundle" or "subscription"), key_prefix, allowance, topup, and, for a key with credits, credits_remaining, credits_total, credits_used, topup_endpoints and, when it also holds an allowance, billing_order.
'401':
description: Missing or invalid API key ("missing_key" / "invalid_key")
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'429':
description: Rate limit exceeded. Applied globally by the server, so any operation can answer it. Honour the Retry-After header; see https://api.ibanforge.com/rate-limits.yml
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
/v1/credits/bundles:
get:
operationId: listCreditBundles
summary: List prepaid credit bundles (free)
description: 'Lists the available prepaid credit bundles with prices. Buy a bundle once via x402 (POST /v1/credits/buy/{bundle}) and receive an API key preloaded with N credits (1 credit = 1 validation/lookup; batch validation debits 1 credit per IBAN) — credits never expire. Card checkout is also available at https://ibanforge.com/pricing. The `subscription` object lists the flat monthly alternative (Pro: 10,000 requests/month by card).'
tags:
- Credits
security: []
responses:
'200':
description: Available bundles
content:
application/json:
schema:
type: object
required:
- bundles
properties:
bundles:
type: array
items:
type: object
properties:
slug:
type: string
enum:
- 1k
- 5k
- 25k
credits:
type: integer
example: 1000
price_usdc:
type: number
example: 5
price_per_call_usdc:
type: number
example: 0.005
buy_endpoint:
type: string
example: POST /v1/credits/buy/1k
payment_method:
type: string
example: x402 USDC on Base mainnet
documentation:
type: string
subscription:
type: object
description: 'The recurring alternative to packs: a flat monthly plan paid by card, key delivered by e-mail after checkout.'
properties:
plan:
type: string
example: pro
monthly_requests:
type: integer
example: 10000
price_usd_per_month:
type: number
example: 29
checkout:
type: string
format: uri
payment_method:
type: string
example: card (Stripe)
'429':
description: Rate limit exceeded. Honour the Retry-After header; see https://api.ibanforge.com/rate-limits.yml
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
/v1/credits/buy/{bundle}:
post:
operationId: buyCreditBundle
summary: Buy a prepaid credit bundle (x402, USDC)
description: 'Pay once via x402 (USDC on Base). Present the API key you already hold (as on any billed route) and the credits land on THAT key: the answer carries same_key: true, api_key echoes the key you presented, and nothing changes in your integration; presenting the key costs no request, and a purchase never grants a free allowance. Without a key (or with an invalid one), you receive a fresh API key preloaded with the bundle credits, recoverable once at recovery_url if the response is lost. Nothing is credited or activated before the payment settles. Bundles: 1k = $4, 5k = $20, 25k = $80. Credits never expire. Optionally pass {"email": "..."} in the body: it becomes the contact of a NEW key; on a recharge it is only kept as the payer''s contact, never attached to the key. Check the balance with GET /v1/credits/balance.'
tags:
- Credits
security:
- x402Payment: []
parameters:
- name: bundle
in: path
required: true
description: Bundle slug
schema:
type: string
enum:
- 1k
- 5k
- 25k
example: 1k
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
email:
type: string
format: email
description: Optional — attach the key to an email address
responses:
'200':
description: 'This payment was already recorded and its purchase was credited or minted (a replayed request): idempotent: true, nothing credited or minted twice. recovery_url only while the key it minted is active and still recoverable'
'201':
description: 'The key you presented was recharged (same_key: true), or a new credit key was minted (shown only once: save it)'
content:
application/json:
schema:
type: object
required:
- api_key
- credits
- bundle
properties:
api_key:
type: string
description: 'Full API key: the key you presented on a recharge, echoed as sent; a new key otherwise, shown only once'
same_key:
type: boolean
description: true when the credits landed on the key you presented
recharged:
type: boolean
key_prefix:
type: string
credits:
type: integer
example: 1000
description: The credits of this bundle
credits_added:
type: integer
example: 1000
description: 'On a recharge: the credits added to the key'
bundle:
type: string
example: 1k
price_paid_usdc:
type: number
example: 4
price_per_call_usdc:
type: number
example: 0.004
first_call:
type: string
description: 'On a new key: a curl command that works with it'
usage_hint:
type: string
balance_endpoint:
type: string
example: GET /v1/credits/balance
recovery_url:
type: string
format: uri
description: 'On a new key: fetch it once if this response is lost'
recovery_note:
type: string
note:
type: string
description: 'Present when the key you sent was invalid or revoked: the pack is on a NEW key'
message:
type: string
'402':
description: 'Payment required (x402): bundle price in USDC. A settlement the facilitator REFUSED ends here too (an explicit reason, nothing broadcast), and nothing is credited'
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'404':
description: Unknown bundle slug — choose 1k, 5k or 25k
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'409':
description: 'This payment was already seen and its purchase was not credited: "payment_pending" (its settlement is not confirmed yet: do NOT pay again), "payment_refused" (refused when it was settled: sign a new payment), "payment_reversed" (refunded or disputed) or "payment_already_used". Nothing is settled again'
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'413':
description: Request body exceeds 256 KB. Applied globally to every operation that takes a body, before routing and before payment, so nothing is charged. Split the input (batch validation accepts up to 100 IBANs per call).
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'429':
description: Rate limit exceeded. Applied globally by the server, so any operation can answer it. Honour the Retry-After header; see https://api.ibanforge.com/rate-limits.yml
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'502':
description: 'settlement_unconfirmed: the outcome of the settlement is unknown (settlement.cause: "timeout", "settlement_pending" when the transfer was broadcast but not confirmed yet, or "facilitator_error" for a network error or a 5xx). The payment may have settled: do NOT pay again. The purchase stays pending and is reconciled by hand once the transfer is confirmed on-chain; settlement.transaction carries the transaction hash when the facilitator returned one'
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
components:
schemas:
ApiError:
type: object
required:
- error
- message
additionalProperties: true
properties:
error:
type: string
description: 'Stable machine-readable token in snake_case, e.g. "invalid_json", "invalid_request", "batch_too_large", "payment_required", "payload_too_large", "rate_limit_exceeded". Branch on this, never on `message`. An invalid IBAN is not an ApiError: validation answers 200 with `valid: false`.'
example: batch_too_large
message:
type: string
description: Human-readable sentence explaining the failure. Wording may change; the token above will not.
example: Maximum 100 IBANs per batch request
securitySchemes:
x402Payment:
type: apiKey
in: header
name: PAYMENT-SIGNATURE
description: x402 USDC micropayment signature (protocol v2). Clients holding v1 payment requirements may send the same signature as X-Payment; both are accepted.
apiKey:
type: http
scheme: bearer
description: API key (Bearer ifk_xxx) — 25 free requests/month without an email address, 200 a month once claimed, or a custom quota for paid keys
accountSession:
type: apiKey
in: cookie
name: ibanforge_account
description: 'Session of the account page, set by POST /v1/account/session: HttpOnly, Secure, SameSite=Strict, Path=/v1/account, 7 days from sign-in. Read-only: it opens no paid route and no route that acts on a key.'
externalDocs:
description: Agent-oriented overview (llms.txt) with copy-paste examples
url: https://api.ibanforge.com/llms.txt
x-provenance:
method: harvested
publisher: IBANforge
source: https://api.ibanforge.com/openapi.json
note: split by refine-openapis from the provider's own published document, verified by fetch (openapi/_original/*.fetch.json);
stamped by stamp-openapi-provenance.py (roadmap#793)