# checksum/v1 — Global checksum/ID validators

Validates common international identifiers by checking their embedded
checksum digit(s) or, for VAT-EU and SWIFT/BIC, their structural format.
Purely offline, deterministic math — no external lookups, no confirmation
that an identifier is *registered* to anyone, only that it is
*well-formed*.

## Request/response shape

All endpoints take the same request shape and return the same base
response shape:

**Request**

```json
{ "value": "4532015112830366" }
```

**Response — valid**

```json
{ "valid": true }
```

**Response — invalid**

```json
{ "valid": false, "reason": "invalid checksum" }
```

Both responses are HTTP 200 — an invalid identifier is a successful
validation that answers "no", not a client error. HTTP 400 with
`{"error": "..."}` is reserved for a malformed request body (bad JSON).

### `POST /v1/checksum/luhn`

Generic Luhn (mod-10) checksum — used by payment card numbers, IMEI
numbers, and similar identifiers. Double every second digit counting from
the right; if the result is greater than 9, subtract 9; the total sum of
all digits must be divisible by 10.

```bash
curl -s -X POST https://apished.com/v1/checksum/luhn \
  -H 'Content-Type: application/json' \
  -d '{"value": "4532015112830366"}'
# {"valid":true}
```

### `POST /v1/checksum/isbn`

10- or 13-character ISBN. ISBN-10 uses weights `10 9 8 7 6 5 4 3 2 1` over
the 10 characters (the last may be `X`, worth 10), sum mod 11 must be 0.
ISBN-13 uses the same checksum as barcodes — see `/ean` below.

```bash
curl -s -X POST https://apished.com/v1/checksum/isbn \
  -H 'Content-Type: application/json' \
  -d '{"value": "0306406152"}'
# {"valid":true}
```

### `POST /v1/checksum/ean`

8-digit (EAN-8), 12-digit (UPC-A), 13-digit (EAN-13), or 14-digit (GTIN-14)
barcode. Alternating weights `1 3` applied right-to-left over all digits
except the last (the check digit); check digit is `(10 - sum mod 10) mod
10`.

```bash
curl -s -X POST https://apished.com/v1/checksum/ean \
  -H 'Content-Type: application/json' \
  -d '{"value": "4006381333931"}'
# {"valid":true}
```

### `POST /v1/checksum/iban`

International Bank Account Number. Checks that the total length matches
the issuing country's registered IBAN length (per the SWIFT IBAN registry),
then verifies the standard mod-97 checksum (move the first 4 characters to
the end, convert letters to numbers `A=10`..`Z=35`, the resulting number
mod 97 must equal 1). Spaces are stripped before validation. Does **not**
decompose the BBAN into a bank code/account number, and does **not**
resolve a BIC.

```bash
curl -s -X POST https://apished.com/v1/checksum/iban \
  -H 'Content-Type: application/json' \
  -d '{"value": "DE89370400440532013000"}'
# {"valid":true}
```

### `POST /v1/checksum/vateu`

EU VAT identification number — **format validation only**, no VIES
registry lookup. Checks the 2-letter member-state prefix (`EL` for Greece,
`XI` for Northern Ireland) against that country's digit/letter pattern.
Covers all 27 EU member states plus Northern Ireland. A format-valid
result does not mean the number is actually registered/active.

```bash
curl -s -X POST https://apished.com/v1/checksum/vateu \
  -H 'Content-Type: application/json' \
  -d '{"value": "DE123456789"}'
# {"valid":true}
```

### `POST /v1/checksum/swiftbic`

SWIFT/BIC bank identifier code — **format validation only**. 8 or 11
characters: 4 letters (bank code) + 2 letters (country code) + 2
alphanumeric (location code) + optional 3 alphanumeric (branch code). The
country code is *not* cross-checked against the ISO 3166-1 list, so a
structurally valid but geographically nonsensical code (e.g. a
non-existent country code) will still pass.

```bash
curl -s -X POST https://apished.com/v1/checksum/swiftbic \
  -H 'Content-Type: application/json' \
  -d '{"value": "DEUTDEFF"}'
# {"valid":true}
```

## Files

- `checksum.go` — module wiring (routes, HTTP handlers)
- `validators.go` — pure checksum/format logic for Luhn, ISBN, EAN/UPC,
  IBAN, VAT-EU, and SWIFT/BIC
- `validators_test.go` — test vectors covering valid, invalid-checksum,
  wrong-length, and malformed-input cases
