SweKit - Swedish validators

Swedish personnummer, orgnr, bankgiro, OCR, account to IBAN and bank days as a read-only remote MCP server.

Hosted MCP Server

npx add-mcp 'https://swekit-api.zenith-ops.workers.dev/mcp'

Installs into Claude Code, Codex, Cursor and more

Documentation

Conventions

  • Validators return {"valid": bool, "errors": [codes]} plus parsed fields. HTTP 200 even if the number is invalid; HTTP 400 only for missing/malformed parameters.
  • Errors: {"error":{"code","message"}}. Rate limit: HTTP 429 with Retry-After.
  • Response header X-Plan: free | pro | gateway.
  • POST example: curl -X POST https://swekit-api.zenith-ops.workers.dev/v1/personnummer -H 'content-type: application/json' -d '{"value":"811218-9876"}'

Access & limits

Anonymous demo: 20 requests/min/IP. Higher limits: send X-API-Key: <license key> (600 req/min). Marketplace subscribers use the marketplace's own key and quota. Pro key: contact the operator; pricing is not published.

curl examples

curl "https://swekit-api.zenith-ops.workers.dev/v1/personnummer?value=811218-9876"
curl -X POST "https://swekit-api.zenith-ops.workers.dev/v1/personnummer" -H 'content-type: application/json' -d '{"value":"811218-9876"}'
curl -H 'X-API-Key: YOUR_KEY' "https://swekit-api.zenith-ops.workers.dev/v1/account?clearing=7507&account=1211203"
# error response (missing parameter)
curl "https://swekit-api.zenith-ops.workers.dev/v1/orgnr"
{"error":{"code":"missing_parameter","message":"Missing parameter: value"}}

Error codes

HTTPCodeMeaning
400missing_parameterRequired input was not supplied
400bad_baseOCR base is invalid
400bad_yearYear must be 1900–2200
400bad_dateDate must be YYYY-MM-DD
400bad_inputBusiness-day input is invalid or out of range
400invalid_jsonPOST body is not valid JSON
401invalid_api_keyAPI key is invalid or expired
429rate_limitedPer-minute quota exceeded
500internal_errorUnexpected server error

MCP client configuration

Claude Desktop (claude_desktop_config.json):

{"mcpServers":{"swekit":{"command":"npx","args":["mcp-remote","https://swekit-api.zenith-ops.workers.dev/mcp"]}}}

Cursor:

{"mcpServers":{"swekit":{"url":"https://swekit-api.zenith-ops.workers.dev/mcp"}}}

VS Code (.vscode/mcp.json):

{"servers":{"swekit":{"type":"http","url":"https://swekit-api.zenith-ops.workers.dev/mcp"}}}

MCP server

Remote MCP endpoint https://swekit-api.zenith-ops.workers.dev/mcp (POST JSON-RPC 2.0: initialize, tools/list, tools/call). Tools: validate_personnummer, validate_orgnr, validate_bankgiro, validate_plusgiro, validate_ocr, generate_ocr, swedish_account_to_iban, validate_iban, lookup_clearing_number, swedish_holidays, swedish_date_info, add_business_days, count_business_days.

Semantics worth knowing

  • Bank accounts: checksum rules per Bankgirot (type 1 variants 1-2 mod-11; type 2 variants 1/3 mod-10, 2/4 mod-11). Swedbank 8xxx accounts are mod-10 "as a rule" and require the 5th clearing digit for IBAN. Plusgiro cannot be converted to IBAN. Some old accounts do not pass checksums.
  • Business days (bank mode): Saturdays, Sundays, public holidays plus midsommarafton, julafton and nyårsafton are not business days (these are equated with Sundays for payment deadlines under Swedish law). Use mode=work for plain weekday-minus-red-day logic. Check your own contracts for company-specific rules.
  • Personnummer: age and century are inferred from the separator (+ = 100+). Gender is from the 9th digit (registered legal sex). Use for validation, not identification.

FAQ

Does a valid number prove an account or person exists?

No. The API checks syntax, dates and checksums only; it is not an identity, ownership or account-existence service.

Are requests stored?

No request data is stored by the service. Use POST for personal numbers so they do not appear in URLs or access logs.

Can I convert Plusgiro to IBAN?

No. Swedish bank accounts can be converted when their clearing range is known; Plusgiro is not a bank account format.

What are the limits?

Anonymous access is 20 requests/minute/IP. A valid Pro key allows 600 requests/minute/key. Pro key: contact the operator; pricing is not published.

Endpoints

GET /v1/personnummer

Validate & parse a Swedish personnummer / samordningsnummer

valuestringPersonnummer in any common format (YYMMDD-NNNC, YYYYMMDDNNNC, with + for 100+). Prefer POST JSON {"value": "..."} so the number never appears in a URL.
curl "https://swekit-api.zenith-ops.workers.dev/v1/personnummer?value=811218-9876&at=2026-10-16"

GET /v1/orgnr

Validate organisationsnummer, derive legal form and Swedish VAT number (SE#########01)

valuestringOrg no. like 556036-0793, 5560360793, SE556036079301
curl "https://swekit-api.zenith-ops.workers.dev/v1/orgnr?value=556036-0793"

GET /v1/bankgiro

Validate bankgiro number (Luhn) and format it

valuestring7-8 digits, with or without dash
curl "https://swekit-api.zenith-ops.workers.dev/v1/bankgiro?value=5402-9681"

GET /v1/plusgiro

Validate plusgiro number

valuestring2-8 digits
curl "https://swekit-api.zenith-ops.workers.dev/v1/plusgiro?value=4-8"

GET /v1/ocr/validate

Validate an OCR / payment reference (Luhn check digit, optional length digit)

valuestringOCR digits
curl "https://swekit-api.zenith-ops.workers.dev/v1/ocr/validate?value=12351"

GET /v1/ocr/generate

Generate an OCR reference from a base number

basestringDigits, e.g. invoice number
length_digitbooleanAdd length digit (default false)
curl "https://swekit-api.zenith-ops.workers.dev/v1/ocr/generate?base=123&length_digit=true"

GET /v1/account

Validate a Swedish bank account (clearing + account, per Bankgirot rules) and convert to IBAN

numberstringFull account digits (clearing first), OR
clearingstringClearing number (4 digits; 5 for Swedbank 8xxx)
accountstringAccount number without clearing
curl "https://swekit-api.zenith-ops.workers.dev/v1/account?clearing=7507&account=1211203"

GET /v1/iban

Validate any IBAN (ISO 13616 mod-97, country length) and identify Swedish banks

valuestringIBAN, spaces allowed
curl "https://swekit-api.zenith-ops.workers.dev/v1/iban?value=SE45 5000 0000 0583 9825 7466"

GET /v1/bic

Validate BIC/SWIFT format

valuestring8 or 11 characters
curl "https://swekit-api.zenith-ops.workers.dev/v1/bic?value=ESSESESS"

GET /v1/clearing

Look up bank, BIC, IBAN id and account type for a clearing number

valuestringFirst 4 digits of the account number
curl "https://swekit-api.zenith-ops.workers.dev/v1/clearing?value=8327"

GET /v1/holidays

Swedish public holidays and eves for a year

yearinteger1900-2200 (default: current year)
curl "https://swekit-api.zenith-ops.workers.dev/v1/holidays?year=2026"

GET /v1/date

Info about a date: weekday (sv/en), ISO week, holiday names, business-day status

datestringYYYY-MM-DD
modestring"bank" (default; midsommarafton, julafton, nyårsafton also excluded) or "work"
curl "https://swekit-api.zenith-ops.workers.dev/v1/date?date=2026-12-24"

GET /v1/business-days/add

Add (or subtract) N business days to a date

datestringYYYY-MM-DD
daysintegerPositive or negative, |n| <= 3650
modestringbank (default) or work
curl "https://swekit-api.zenith-ops.workers.dev/v1/business-days/add?date=2026-12-22&days=2"

GET /v1/business-days/between

Count business days between two dates

fromstringYYYY-MM-DD
tostringYYYY-MM-DD
modestringbank (default) or work
curl "https://swekit-api.zenith-ops.workers.dev/v1/business-days/between?from=2026-10-16&to=2026-11-16"

Data sources

  • Bankgirot, Bankernas kontonummer, 2024-02-22.
  • Bankinfrastruktur i Sverige AB, IBAN and Swedish national account number page (clearing table, data date 2026-10-16).
  • Holidays: computed (Meeus/Jones/Butcher Easter algorithm + statutory rules).