{
  "openapi": "3.1.0",
  "info": {
    "title": "TestCards API",
    "version": "1.0.0",
    "summary": "BIN/IIN lookup, Luhn validation, and QA test-card generation.",
    "description": "A tiny, pure-compute API for software testing and QA. Detect a card scheme from a BIN, validate a number against the Luhn (mod-10) checksum, or generate format-valid, non-functional test fixtures. For software testing only: generated numbers pass the Luhn check but are not issued to anyone, hold no funds, and are declined by every real payment processor. No real cardholder data or PII is stored. Do not use this API for fraud, \"carding,\" or to bypass any payment control. Those uses are prohibited.",
    "contact": {
      "name": "TestCards",
      "url": "https://www.testcards.io"
    },
    "license": {
      "name": "Issuer sample: CC-BY (bin-list-data)",
      "url": "https://github.com/venelinkochev/bin-list-data"
    }
  },
  "servers": [
    {
      "url": "https://www.testcards.io",
      "description": "Production"
    }
  ],
  "tags": [
    { "name": "BIN", "description": "Card scheme / length detection from a BIN/IIN." },
    { "name": "Luhn", "description": "Luhn (mod-10) checksum validation." },
    { "name": "Generate", "description": "Format-valid, non-functional QA test fixtures." }
  ],
  "security": [
    { "apiKeyQuery": [] },
    { "bearerAuth": [] }
  ],
  "paths": {
    "/api/v1/bin": {
      "get": {
        "tags": ["BIN"],
        "operationId": "lookupBin",
        "summary": "Look up a BIN / IIN",
        "description": "Returns the scheme, valid lengths, and CVV length computed from the IIN. Issuer, type, and country are populated only for prefixes in the bundled CC-BY sample. This is a QA helper, not a comprehensive BIN database.",
        "parameters": [
          {
            "name": "bin",
            "in": "query",
            "required": true,
            "description": "A BIN/IIN (first 6–8 digits) or a full card number. Non-digit characters are ignored. The `number` query param is accepted as an alias.",
            "schema": { "type": "string", "examples": ["424242"] }
          },
          { "$ref": "#/components/parameters/KeyParam" }
        ],
        "responses": {
          "200": {
            "description": "BIN metadata.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/BinResult" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "422": { "$ref": "#/components/responses/Unrecognized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/v1/luhn": {
      "get": {
        "tags": ["Luhn"],
        "operationId": "validateLuhn",
        "summary": "Validate a number with the Luhn algorithm",
        "description": "Checks the mod-10 checksum and detects the scheme. A structural check only. It does not indicate whether a card is real, active, or has funds.",
        "parameters": [
          {
            "name": "number",
            "in": "query",
            "required": true,
            "description": "The card number to validate. Non-digit characters are ignored. The `card` query param is accepted as an alias.",
            "schema": { "type": "string", "examples": ["4242424242424242"] }
          },
          { "$ref": "#/components/parameters/KeyParam" }
        ],
        "responses": {
          "200": {
            "description": "Luhn and scheme result.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/LuhnResult" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/v1/generate": {
      "get": {
        "tags": ["Generate"],
        "operationId": "generateTestCards",
        "summary": "Generate QA test-card fixtures",
        "description": "Returns Luhn-valid, format-valid card numbers for a network, for use as software test fixtures. These numbers are NOT issued to anyone and are declined by every real payment processor. Do not use them to attempt a transaction, for fraud, or to bypass any payment control.",
        "parameters": [
          {
            "name": "network",
            "in": "query",
            "required": false,
            "description": "Card network to generate for. Defaults to visa.",
            "schema": {
              "type": "string",
              "default": "visa",
              "enum": ["visa", "mastercard", "amex", "discover", "diners", "jcb", "unionpay", "maestro"]
            }
          },
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "How many numbers to generate, 1–50.",
            "schema": { "type": "integer", "minimum": 1, "maximum": 50, "default": 1 }
          },
          { "$ref": "#/components/parameters/KeyParam" }
        ],
        "responses": {
          "200": {
            "description": "Generated fixtures.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/GenerateResult" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKeyQuery": {
        "type": "apiKey",
        "in": "query",
        "name": "key",
        "description": "Free API key passed as the `key` query parameter. Get one at https://www.testcards.io/#get-key. The free tier allows 1,000 calls per month with no card."
      },
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Free API key passed as `Authorization: Bearer <key>`. Get one at https://www.testcards.io/#get-key. The free tier allows 1,000 calls per month with no card."
      }
    },
    "parameters": {
      "KeyParam": {
        "name": "key",
        "in": "query",
        "required": false,
        "description": "Your API key. May be omitted if sent via the `Authorization: Bearer <key>` header instead.",
        "schema": { "type": "string", "examples": ["YOUR_KEY"] }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Missing or invalid parameter.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "Unauthorized": {
        "description": "Missing or invalid API key.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "Unrecognized": {
        "description": "The card number / BIN does not match any known scheme.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "RateLimited": {
        "description": "Monthly quota for the key has been reached.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": { "type": "string", "description": "Human-readable error reason." }
        },
        "required": ["error"]
      },
      "BinResult": {
        "type": "object",
        "properties": {
          "bin": { "type": "string", "description": "The leading BIN/IIN digits (up to 8)." },
          "scheme": { "type": "string", "description": "Network id, e.g. visa, mastercard." },
          "brand": { "type": "string", "description": "Human-readable network/brand label." },
          "type": {
            "type": ["string", "null"],
            "enum": ["credit", "debit", "prepaid", null],
            "description": "Card type, only for known sample BINs; null otherwise."
          },
          "bank": { "type": ["string", "null"], "description": "Issuer label, only for known sample BINs." },
          "country": { "type": ["string", "null"], "description": "ISO 3166-1 alpha-2 country, only for known sample BINs." },
          "lengths": { "type": "array", "items": { "type": "integer" }, "description": "Valid total PAN lengths for this network." },
          "cvvLength": { "type": "integer", "description": "Expected CVV/CVC/CID length." },
          "note": { "type": "string" }
        },
        "required": ["bin", "scheme", "brand", "lengths", "cvvLength"]
      },
      "LuhnResult": {
        "type": "object",
        "properties": {
          "number": { "type": "string", "description": "The digits that were checked." },
          "luhnValid": { "type": "boolean", "description": "Whether the number passes the Luhn checksum." },
          "scheme": { "type": ["string", "null"], "description": "Detected network id, or null if unknown." },
          "brand": { "type": ["string", "null"], "description": "Human-readable brand label, or null." },
          "lengthValid": { "type": ["boolean", "null"], "description": "Whether the length is valid for the scheme; null when the scheme is unknown." }
        },
        "required": ["number", "luhnValid"]
      },
      "GenerateResult": {
        "type": "object",
        "properties": {
          "network": { "type": "string" },
          "count": { "type": "integer" },
          "cards": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "number": { "type": "string", "description": "Format-valid, non-functional test PAN." },
                "formatted": { "type": "string", "description": "The number grouped for display." },
                "valid": { "type": "boolean", "description": "Always true: the number passes the Luhn check." }
              },
              "required": ["number", "formatted", "valid"]
            }
          },
          "disclaimer": { "type": "string", "description": "Test-fixtures-only notice." }
        },
        "required": ["network", "count", "cards"]
      }
    }
  }
}
