ibanchecker

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 11, 2026 License: MIT Imports: 10 Imported by: 0

README

ibanchecker-go

Official Go client for the ibanchecker.cash IBAN validation API.

Validate IBANs across 92 countries, validate up to 100 IBANs per request, extract IBANs from free text, look up country format specifications, and resolve SWIFT/BIC codes. No IBAN data is stored or logged; all validation runs in memory at the edge.

Go Reference

Install

go get github.com/koraykoylu/ibanchecker-go

Requires Go 1.21 or newer. There are no dependencies: the client is built on net/http and encoding/json from the standard library.

Quick start

package main

import (
	"context"
	"fmt"
	"log"

	ibanchecker "github.com/koraykoylu/ibanchecker-go"
)

func main() {
	client := ibanchecker.New("") // no API key needed for light use (100 requests/hour per IP)

	result, err := client.Validate(context.Background(), "DE89 3704 0044 0532 0130 00")
	if err != nil {
		log.Fatal(err)
	}

	if result.Valid {
		fmt.Println(result.CountryName) // Germany
		fmt.Println(result.BankName)    // Commerzbank AG Cologne
		fmt.Println(result.BIC)         // COBADEFFXXX
	} else {
		fmt.Println(result.Error)     // human-readable reason
		fmt.Println(result.ErrorCode) // e.g. INVALID_COUNTRY
	}
}

Every method takes a context.Context as its first argument, so a caller's deadline and cancellation reach the request.

Authentication

An API key is optional. Without one, requests are limited to 100 per hour per IP. With a key, requests count against your plan quota. Get a free key at ibanchecker.cash/api-docs.

client := ibanchecker.New("iban_your_api_key")
client := ibanchecker.New(os.Getenv("IBANCHECKER_API_KEY"))

Methods

Method Description
Validate(ctx, iban) Validate a single IBAN. Returns a *ValidationResult.
ValidateBulk(ctx, ibans) Validate up to 100 IBANs. Returns a *BatchResult.
Extract(ctx, text) Find and validate IBANs in free text (up to 50,000 chars). Returns a *BatchResult.
CountryFormat(ctx, country) IBAN format spec for an ISO country code. Returns a *FormatSpec.
LookupBIC(ctx, bic) Resolve an 8 or 11 character BIC. Returns a *BankRecord.
Bulk validation
batch, err := client.ValidateBulk(ctx, []string{
	"DE89370400440532013000",
	"GB29NWBK60161331926819",
	"XX00",
})
if err != nil {
	log.Fatal(err)
}

fmt.Println(batch.ValidCount, "of", batch.Count, "valid")

for _, r := range batch.Results { // results come back in input order
	fmt.Println(r.IBAN, r.Valid)
}
Extract from text
batch, err := client.Extract(ctx, "Please wire to DE89 3704 0044 0532 0130 00 by Friday.")
for _, r := range batch.Results {
	fmt.Println(r.IBAN, r.BankName)
}
Country format and BIC lookup
spec, err := client.CountryFormat(ctx, "DE")
fmt.Println(spec.Length, spec.Example) // 22 DE89370400440532013000

for _, f := range spec.BbanFields {
	fmt.Printf("%s (%d)\n", f.Label, f.Length) // BLZ (8), Account No. (10)
}

bank, err := client.LookupBIC(ctx, "DEUTDEFF")
fmt.Println(bank.BankName, bank.City) // Deutsche Bank AG Frankfurt  FRANKFURT AM MAIN
Tri-state fields are pointers

NationalCheckValid, SEPA and SWIFT are *bool, not bool. The API distinguishes false from absent and Go's zero value cannot, so a nil pointer means "not known for this IBAN" rather than "no".

result, err := client.Validate(ctx, "DE84100100100532013000")
if result.Valid && result.NationalCheckValid != nil && !*result.NationalCheckValid {
	fmt.Println("Valid IBAN, but the account number looks mistyped.")
}

NationalCheckValid reports a domestic account check digit run on top of the ISO 13616 checksum, such as Germany's per-bank Prüfziffer or the UK sort-code and account modulus check. It is advisory: an IBAN with Valid true is a valid IBAN whatever this says.

Error handling

A malformed IBAN is not an error: Validate returns a *ValidationResult with Valid false. Errors come back for transport, authentication, quota and server-side problems only.

Compare with errors.Is for the common branches, and reach for errors.As when you need the detail:

bank, err := client.LookupBIC(ctx, "ZZZZZZZZ")
switch {
case errors.Is(err, ibanchecker.ErrNotFound):
	fmt.Println("No bank for that BIC")
case errors.Is(err, ibanchecker.ErrRateLimit):
	fmt.Println("Slow down")
case errors.Is(err, ibanchecker.ErrAuthentication):
	fmt.Println("Check your API key")
}

var apiErr *ibanchecker.Error
if errors.As(err, &apiErr) {
	fmt.Println(apiErr.Status, apiErr.Code, apiErr.Message, apiErr.Response)
}
Sentinel Returned when
ErrBadRequest HTTP 400, the request was malformed
ErrAuthentication HTTP 401, the API key is missing, invalid or inactive
ErrNotFound HTTP 404, no such country code or BIC
ErrRateLimit HTTP 429, hourly limit or monthly quota exceeded
ErrAPI any other error status, or a body that could not be read
ErrTransport the request never reached the API: DNS, TLS, connection, timeout

Timeouts and your own HTTP stack

client := ibanchecker.New("", ibanchecker.WithTimeout(3*time.Second))

client := ibanchecker.New("", ibanchecker.WithHTTPClient(myClient))

WithHTTPClient replaces the whole client, so the timeout and the redirect policy below come from yours.

Redirects are refused, not followed

The default client stops at a redirect and returns an ErrTransport naming the target. That is deliberate, for two reasons. net/http turns a POST into a GET on a 301, as the RFC asks, so an http:// base URL would reach the https endpoint as a GET and come back 405 Method Not Allowed with nothing to explain it. And a redirect to another host is how an API key travels somewhere it was never meant to go.

Use an https base URL and the situation does not arise.

Raw responses

Every model keeps the untouched response body in Raw, so a field added to the API later is reachable without waiting for a client release.

result, _ := client.Validate(ctx, "DE89370400440532013000")
fmt.Println(result.Raw["transfer_type"]) // SEPA+SWIFT

Tests

go test ./...

The suite runs against httptest servers, so it needs no network.

Clients for other languages: Python, PHP, JavaScript, Ruby, and an MCP server.

License

MIT

Documentation

Overview

Package ibanchecker is the official Go client for the ibanchecker.cash IBAN validation API.

Validate IBANs across 92 countries, validate up to 100 IBANs per request, extract IBANs from free text, look up country format specifications and resolve SWIFT/BIC codes.

An API key is optional. Without one, requests are limited to 100 per hour per IP. Get a free key at https://ibanchecker.cash/api-docs.

client := ibanchecker.New("") // or ibanchecker.New("iban_your_key")

result, err := client.Validate(context.Background(), "DE89 3704 0044 0532 0130 00")
if err != nil {
	log.Fatal(err)
}
if result.Valid {
	fmt.Println(result.BankName, result.BIC)
}

A malformed IBAN is not an error: Validate returns a ValidationResult with Valid false and an Error plus ErrorCode explaining why. Errors are returned for transport, authentication, quota and server-side problems only.

Index

Constants

View Source
const DefaultBaseURL = "https://ibanchecker.cash/api/v1"

DefaultBaseURL is the production API.

View Source
const Version = "0.1.0"

Version goes out in the User-Agent header.

Variables

View Source
var (
	// ErrBadRequest is returned for HTTP 400: the request was malformed.
	ErrBadRequest = errors.New("bad request")

	// ErrAuthentication is returned for HTTP 401: the API key is missing,
	// invalid or inactive.
	ErrAuthentication = errors.New("authentication failed")

	// ErrNotFound is returned for HTTP 404: no such country code or BIC.
	ErrNotFound = errors.New("not found")

	// ErrRateLimit is returned for HTTP 429: the hourly rate limit or the
	// monthly quota was exceeded.
	ErrRateLimit = errors.New("rate limited")

	// ErrAPI is returned for any other error status, and for a response body
	// that could not be read as JSON.
	ErrAPI = errors.New("api error")

	// ErrTransport is returned when the request never reached the API: DNS,
	// TLS, connection or timeout.
	ErrTransport = errors.New("transport error")
)

Sentinel errors for the failures a caller usually branches on. Compare them with errors.Is; reach for errors.As and *Error when you need the status, the machine-readable code or the decoded body.

Functions

This section is empty.

Types

type BankRecord

type BankRecord struct {
	BIC          string `json:"bic"`
	BIC8         string `json:"bic8"`
	BankCode     string `json:"bank_code"`
	CountryCode  string `json:"country_code"`
	LocationCode string `json:"location_code"`
	BranchCode   string `json:"branch_code"`
	BankName     string `json:"bank_name"`
	City         string `json:"city"`
	CountryName  string `json:"country_name"`

	SEPA   *bool  `json:"sepa"`
	Type   string `json:"type"`
	Status string `json:"status"`

	// Raw is the untouched response body.
	Raw map[string]any `json:"-"`
}

BankRecord is the institution behind a SWIFT/BIC code.

func (*BankRecord) UnmarshalJSON

func (b *BankRecord) UnmarshalJSON(data []byte) error

type BatchResult

type BatchResult struct {
	Count        int                `json:"count"`
	ValidCount   int                `json:"valid_count"`
	InvalidCount int                `json:"invalid_count"`
	Results      []ValidationResult `json:"results"`

	// Raw is the untouched response body.
	Raw map[string]any `json:"-"`
}

BatchResult is the result of a bulk validation or a text extraction. Results come back in the same order as the input.

func (*BatchResult) UnmarshalJSON

func (b *BatchResult) UnmarshalJSON(data []byte) error

type BbanField

type BbanField struct {
	Label       string `json:"label"`
	Length      int    `json:"length"`
	Type        string `json:"type"`
	Description string `json:"description"`

	// Raw is the untouched field object.
	Raw map[string]any `json:"-"`
}

BbanField is one segment of a country's BBAN, in the order it appears in the IBAN.

func (*BbanField) UnmarshalJSON

func (f *BbanField) UnmarshalJSON(data []byte) error

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client talks to the ibanchecker.cash API. The zero value is not usable; call New. A Client is safe for concurrent use by multiple goroutines.

func New

func New(apiKey string, opts ...Option) *Client

New returns a Client. Pass an empty apiKey for unauthenticated use.

func (*Client) CountryFormat

func (c *Client) CountryFormat(ctx context.Context, country string) (*FormatSpec, error)

CountryFormat returns the IBAN format specification for an ISO 3166-1 alpha-2 country code, for example "DE".

func (*Client) Extract

func (c *Client) Extract(ctx context.Context, text string) (*BatchResult, error)

Extract scans free text (emails, invoices) for IBAN-shaped strings and validates each candidate. Up to 50,000 characters per request.

func (*Client) LookupBIC

func (c *Client) LookupBIC(ctx context.Context, bic string) (*BankRecord, error)

LookupBIC resolves an 8 or 11 character ISO 9362 BIC to a bank record.

func (*Client) Validate

func (c *Client) Validate(ctx context.Context, iban string) (*ValidationResult, error)

Validate validates a single IBAN.

A malformed IBAN is not an error: the result comes back with Valid false and an Error plus ErrorCode explaining why.

func (*Client) ValidateBulk

func (c *Client) ValidateBulk(ctx context.Context, ibans []string) (*BatchResult, error)

ValidateBulk validates up to 100 IBANs in one request. Results come back in the same order as the input.

type Error

type Error struct {
	// Status is the HTTP status, or 0 when the request never completed.
	Status int

	// Code is the machine-readable code from the API body, for example
	// "BIC_NOT_FOUND". Empty when the API sent none.
	Code string

	// Message is the human-readable reason.
	Message string

	// Response is the decoded response body, when the API sent one.
	Response map[string]any
	// contains filtered or unexported fields
}

Error carries everything the API said about a failure.

A malformed IBAN is not an error: Validate returns a ValidationResult with Valid false. These are returned for transport, authentication, quota and server-side problems only.

func (*Error) Error

func (e *Error) Error() string

func (*Error) Unwrap

func (e *Error) Unwrap() error

Unwrap reports the sentinel, so errors.Is(err, ErrNotFound) works.

type FormatSpec

type FormatSpec struct {
	CountryCode  string `json:"country_code"`
	CountryName  string `json:"country_name"`
	Length       int    `json:"length"`
	Currency     string `json:"currency"`
	CurrencyName string `json:"currency_name"`

	SEPA  *bool `json:"sepa"`
	SWIFT *bool `json:"swift"`

	FormatString string      `json:"format_string"`
	Example      string      `json:"example"`
	BbanFields   []BbanField `json:"bban_fields"`

	// Raw is the untouched response body.
	Raw map[string]any `json:"-"`
}

FormatSpec is the IBAN format specification for one country.

func (*FormatSpec) UnmarshalJSON

func (s *FormatSpec) UnmarshalJSON(data []byte) error

type Option

type Option func(*Client)

Option configures a Client.

func WithBaseURL

func WithBaseURL(baseURL string) Option

WithBaseURL points the client at a different host. Any trailing slash is trimmed.

func WithHTTPClient

func WithHTTPClient(hc *http.Client) Option

WithHTTPClient replaces the HTTP client, which is how an application routes these calls through its own stack, and how the tests run against an httptest server. It also overrides WithTimeout and the redirect policy below, so set both on the client you pass in.

func WithTimeout

func WithTimeout(d time.Duration) Option

WithTimeout sets the timeout on the default HTTP client.

type ValidationResult

type ValidationResult struct {
	Valid       bool   `json:"valid"`
	IBAN        string `json:"iban"`
	Formatted   string `json:"formatted"`
	CheckDigits string `json:"check_digits"`
	BBAN        string `json:"bban"`
	Country     string `json:"country"`
	CountryName string `json:"country_name"`

	BankName      string `json:"bank_name"`
	BankType      string `json:"bank_type"`
	BIC           string `json:"bic"`
	BankCity      string `json:"bank_city"`
	BankCode      string `json:"bank_code"`
	BranchCode    string `json:"branch_code"`
	AccountNumber string `json:"account_number"`

	// NationalCheckValid reports a domestic account check digit run on top of
	// the ISO 13616 checksum, such as Germany's per-bank Pruefziffer or the UK
	// sort-code and account modulus check. It is advisory: an IBAN with Valid
	// true is a valid IBAN whatever this says. False usually means a
	// transcription error in the account number. Nil where the country has no
	// such scheme.
	NationalCheckValid *bool `json:"national_check_valid"`

	Currency     string `json:"currency"`
	CurrencyName string `json:"currency_name"`
	TransferType string `json:"transfer_type"`

	// SEPA reports whether the IBAN's country is in the SEPA zone. Nil when
	// the API did not say.
	SEPA *bool  `json:"sepa"`
	Flag string `json:"flag"`

	// Error and ErrorCode explain why Valid is false.
	Error     string `json:"error"`
	ErrorCode string `json:"error_code"`

	// Raw is the untouched response body, so a field added to the API later is
	// reachable without waiting for a client release.
	Raw map[string]any `json:"-"`
}

ValidationResult is the result of validating one IBAN.

Valid is the primary flag. When it is false only IBAN, Formatted, Country, CountryName, Error and ErrorCode are populated.

func (*ValidationResult) UnmarshalJSON

func (r *ValidationResult) UnmarshalJSON(data []byte) error

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL