api.ckonto.de  |  ckonto.de

Overview

Base URL: https://api.ckonto.de

Version: v1  (all endpoints start with /v1/)

Format: JSON (Content-Type: application/json)

Discovery: /service  |  OpenAPI 3.0 Schema

Field order: fields are returned in a fixed, documented order (see the examples below). Per RFC 8259, however, the order of JSON object fields carries no meaning; clients must not rely on it and must ignore unknown additional fields so that future extensions remain compatible.

Authentication

All endpoints (except /service, /service/openapi.json, and /v1/ping//v1/test) require a valid API key as a bearer token:

Authorization: Bearer API_KEY

Alternatively via the X-API-Key: API_KEY header. The key is passed exclusively via header - not as a query parameter and not in the request body. This keeps it out of server logs, browser histories, and Referer headers.

/v1/ping and /v1/test are deliberately reachable without authentication (intended for health checks/monitoring). A token sent anyway is ignored and not checked.

You can get an API key via ckonto.de/bestellung.htm.

Note: the auth check runs before any other validation on all protected endpoints. If the key is missing or invalid, you always get 401 invalid_key back - even if the request also uses the wrong HTTP method, a malformed path, or missing parameters (which would otherwise return 405 method_not_allowed or 400). With a valid key, the respective structural error is reported as documented.

Endpoints

Check account number / bank code

GET /v1/kto/{kontonummer}/{bankleitzahl}
POST /v1/kto

Checks a German account number and bank code (BLZ). Optionally with IBAN generation (sepa=1).

Example GET

curl -H "Authorization: Bearer API_KEY" \
  "https://api.ckonto.de/v1/kto/0532013000/37040044"

Example POST

curl -H "Authorization: Bearer API_KEY" \
     -H "Content-Type: application/json" \
     -d '{"kontonummer":"0532013000","bankleitzahl":"37040044"}' \
  "https://api.ckonto.de/v1/kto"

Response

{
  "status": 1,
  "message": "The bank account details are valid",
  "data": {
    "iban": null,
    "bic": null,
    "kto": "0532013000",
    "blz": "37040044",
    "bank": "Commerzbank",
    "zip": "50447",
    "location": "Köln",
    "country": "DE"
  }
}

With sepa=1 (GET: query parameter, POST: in the JSON body), iban and bic are also returned. Only 0 and 1 are allowed; other values return HTTP 400 with code invalid_sepa. If the parameter is missing, the default 0 applies.

country always contains the ISO 3166-1 alpha-2 country code of the bank (e.g. DE), not the spelled-out country name. If no code can be determined, the field is an empty string.

ccd (optional, GET: query parameter, POST: in the JSON body): a 2-letter country code that controls IBAN generation from account number/bank code for countries outside Germany. Supported: DE, AT, CH, BE, CZ, SK, ES (case-insensitive, other values are ignored). Affects the response field country independently of sepa.

Important: kontonummer and bankleitzahl must be in the country-specific format - not necessarily 8 digits like a German bank code. ccd alone only sets country - for the generated iban/bic, also set sepa=1. Example for Slovakia:

curl -H "Authorization: Bearer API_KEY" \
  "https://api.ckonto.de/v1/kto/5207004203041425/8360?ccd=SK&sepa=1"
{
  "status": 1,
  "message": "The bank account details are valid",
  "data": {
    "iban": "SK4283605207004203041425",
    "bic": "BREXSKBXXXX",
    "kto": "5207004203041425",
    "blz": "8360",
    "bank": "mBank S.A., pobočka zahraničnej banky",
    "zip": "SK-81109",
    "location": "Bratislava",
    "country": "SK"
  }
}

Check IBAN

GET /v1/iban/{iban}
GET /v1/iban/{iban}/{bic}
POST /v1/iban

Checks an IBAN (international, focus on DE/AT/CH/EU). Optionally with BIC validation. Also available as a batch of up to 500 IBANs via POST.

iban and bic are always returned by this endpoint - a sepa parameter is syntactically accepted here but has no effect (unlike the account number/bank code check, where sepa=1 is required to enable it).

Example GET

curl -H "Authorization: Bearer API_KEY" \
  "https://api.ckonto.de/v1/iban/DE89370400440532013000"

Response (single check)

{
  "status": 1,
  "message": "The IBAN is valid",
  "data": {
    "iban": "DE89370400440532013000",
    "bic": "COBADEFFXXX",
    "kto": "0532013000",
    "blz": "37040044",
    "bank": "Commerzbank",
    "zip": "DE-50447",
    "location": "Köln",
    "country": "DE",
    "sepa_methods": {
      "sct": 1,
      "sdd": 1,
      "b2b": 1,
      "scc": 1
    }
  }
}

sepa_methods shows which SEPA payment methods the bank supports: sct (credit transfer), sdd (direct debit), b2b (business-to-business direct debit), scc (cards clearing). Value 1 = supported, 0 = not supported, 9 = cannot be determined (incomplete bank master data for this country, mostly occurs outside DE/AT/CH).

country always contains the ISO 3166-1 alpha-2 country code of the bank (e.g. DE, AT, CH), not the spelled-out country name. If no code can be determined, the field is an empty string.

Example POST – single check with BIC

curl -H "Authorization: Bearer API_KEY" \
     -H "Content-Type: application/json" \
     -d '{"iban":"DE89370400440532013000","bic":"COBADEFFXXX"}' \
  "https://api.ckonto.de/v1/iban"

Negative examples (each a different status/error)

IBANResultReason
DE00370400440532013000HTTP 200, status: 0Incorrect IBAN check digit (otherwise identical to the valid example above)
DE93999999990000000001HTTP 200, status: 7Bank code (BLZ) does not exist
XXHTTP 400, invalid_ibanFormat error - too short / not a valid country prefix

The first two cases are not errors in the HTTP sense (HTTP 200) - the request was syntactically correct, the business check result is "invalid" or "bank code unknown" respectively. Only the third case is a genuine request error (HTTP 400), because the IBAN does not even match the basic format.

Example POST – batch (up to 500 IBANs)

curl -H "Authorization: Bearer API_KEY" \
     -H "Content-Type: application/json" \
     -d '{"ibans":["DE89370400440532013000","AT001234512345678901"]}' \
  "https://api.ckonto.de/v1/iban"

Batch response

Counting: every IBAN in a batch counts as one request - including entries that already fail the format check.

Every element in batch.results always contains iban, valid, status, and data - even if the IBAN is not valid from a business perspective (e.g. status: 7, "bank code does not exist"). This is not an error and carries no error object. An error object only appears if this item could not be checked at all (format error or backend failure); it has a flat structure and, like the other error objects, uses the field code (not error_code).

{
  "status": 1,
  "message": "Batch processing completed",
  "batch": {
    "total": 3,
    "results": [
      { "status": 1, "iban": "DE89370400440532013000", "valid": true,  "data": { "country": "DE", "sepa_methods": { "sct": 1, "sdd": 1, "b2b": 1, "scc": 1 }, ... } },
      { "status": 7, "iban": "DE93999999990000000001", "valid": false, "data": { "country": "DE", ... } },
      { "status": 0, "iban": "XX",                     "valid": false, "data": { "country": "", ... },
        "error": { "code": "invalid_iban", "message": "The IBAN is invalid or has an incorrect format", "field": "iban" } }
    ]
  }
}

Bank search

GET /v1/search?name=&location=&zip=&bankleitzahl=&max=
POST /v1/search

Searches banks by name, location, postal code, or bank code. At least one of the fields name, location, zip, or bankleitzahl must be set - without any search criterion, the API returns HTTP 400 with code missing_search_criteria. Maximum 50 results.

max limits the number of results (1-50). If max is missing, the default 10 applies. Values outside 1-50 or non-numeric values return HTTP 400 with code invalid_max.

Note: if the search finds at least as many results as requested via max (i.e. the result list was truncated by max), status: 9 is returned instead of status: 1 - with an otherwise identical response structure (results.count/results.items still populated, HTTP 200). This is intentional behavior of the cKonto search and not an error; it merely indicates that further results, not included here, may exist. To get all results, increase max or narrow the search criteria (name, location, zip, bankleitzahl) further.
Note: name and location are AND-combined and are each matched as a substring (case-insensitive) against the bank master data. Example: location=Berlin also returns "Bernau bei Berlin" and "Überlingen", because both locations contain the substring "berlin". This is intentional behavior.
Note: every search criterion has a minimum length: name/location 3 characters, zip 2 characters, bankleitzahl 4 characters. This is not an HTTP error - a value that is too short still returns HTTP 200 with an empty result and the matching business error status (status: 2/3/4/8, see the business status table below).
Limitation: live testing confirms name and location only accept plain letters - no digit (not even combined with letters), no umlaut, no ß, no space. The vendor documentation describes the fields as "alphanumeric"; in practice, every digit is rejected regardless of position. A value that is too short or not allowed returns HTTP 200 with status: 3/4 instead of a result. Examples: location=Köln, name=Postbank1, and name=Deutsche Bank (multi-word) fail; location=Koeln and name=Deutsche work. This is a limitation of the cKonto search function itself, not an encoding issue in the wrapper.

Example GET

curl -H "Authorization: Bearer API_KEY" \
  "https://api.ckonto.de/v1/search?name=Sparkasse&location=Berlin&max=5"

Response

{
  "status": 1,
  "message": "The search was successful",
  "results": {
    "count": 4,
    "items": [
      { "bic": "BELADEBEXXX", "blz": "10050000", "bank": "BSK 1818 - Berliner Sparkasse", "zip": "10889", "location": "Berlin" },
      ...
    ]
  }
}

As everywhere else, status here is a numeric value (not a string).

Health check

GET /v1/ping
GET /v1/test

Checks whether the service is reachable. /v1/test additionally indicates test mode. No bearer token required - both endpoints are deliberately reachable without authentication (health check/monitoring). A token sent anyway is ignored.

{ "status": 1, "message": "Pong" }

Errors

Errors are always returned as a JSON object with the key error. A complete list of all error codes with descriptions and examples can be found at /api/docs/en/errors.

{
  "error": {
    "http_status": 401,
    "code": "invalid_key",
    "message": "The API key is not valid"
  }
}
Stable and machine-readable: for business check results, status (0-9, see below); for API/HTTP errors, error.code and error.http_status. In both cases, message is English free text without any stability guarantee - for display only, do not use it in program logic.

Business status codes

The status field in a success response contains the business check status from cKonto:

CodeMeaning
0Account number/IBAN not valid / no results for this search
1Bank account details valid
2Bank code (BLZ) must be 8 digits / invalid input: postal code
3Invalid input: account number / invalid input: location
4Errors in account number and bank code / invalid input: IBAN / invalid input: name
7Bank code (BLZ) does not exist / invalid input: max
8Demo mode / invalid input: bank code (BLZ)
9Bank account details cannot be verified / output limit reached

Response headers

HeaderDescription
X-Request-IDUnique ID for the request - can be sent by the client and is mirrored back (only [A-Za-z0-9-], other characters are removed, truncated to 64 characters); otherwise generated server-side. For log correlation and debugging.
X-RateLimit-LimitMaximum requests per time window
X-RateLimit-WindowWindow size in seconds
X-RateLimit-PolicyRate limit policy as plain text, e.g. "60 requests per 10 seconds". The limit is not applied per API key.
X-Idempotency-KeyMirrored back if sent by the client (truncated to 64 characters). Purely a correlation value - no server-side deduplication takes place; a repeated POST with the same key is processed in full again.
Tip: send your own X-Request-ID header in the request (e.g. a UUID) so you can uniquely track your requests in logs.