PHP integration guide
Validate an IBAN in a PHP form
Build a small server-side form that checks an IBAN with IBAN-Test, keeps your API token out of the browser, and gives customers useful feedback when a check cannot be completed.
This guide uses PHP 8.2 or later with cURL and sessions. The download contains a working form, a separate API client, offline tests and setup instructions. It is a local learning example: add application authentication and a shared rate limit before publishing an endpoint that spends your API quota.
1. Understand the request lifecycle
The browser displays an ordinary HTML form. Submitting it sends the IBAN and a session CSRF token to your PHP application. PHP checks the form token, limits the input, and removes ordinary spaces before making the API request. The browser never connects directly to IBAN-Test and never receives the Bearer token.
The backend sends JSON to POST https://www.iban-test.eu/api/v2/iban/validate. It reads the HTTP status and JSON fields, maps the result to a controlled user message, and returns another HTML page. The API contract is documented in the IBAN-Test API documentation.
Browser form → your PHP backend → IBAN-Test API
Browser result ← controlled message ← HTTP status and JSON
Keep this boundary when adapting the example to AJAX: JavaScript may call your own application, but authentication with IBAN-Test still belongs on the server. Hiding a token in a JavaScript file or minified bundle does not make it secret.
2. Start the example locally
Extract the ZIP and change into its demo directory. Run php -v and php -m to confirm the PHP version and cURL extension. Sessions and JSON must also be available. No Composer installation is required. Run the included offline checks first:
php tests/run.php
For an actual API check, obtain a token from your IBAN-Test account. In Bash, use a hidden prompt so the value is not entered as a literal command in shell history:
read -r -s -p 'IBAN-Test API token: ' IBAN_TEST_API_TOKEN
printf '\n'
export IBAN_TEST_API_TOKEN
php -d display_errors=0 -d post_max_size=4K -S 127.0.0.1:8080 -t public
Open http://127.0.0.1:8080. The server listens only on your machine. Stop it with Ctrl+C and run unset IBAN_TEST_API_TOKEN afterwards. PHP's development server is intended for this local exercise. Keep public as the document root so the client, tests and README sit outside the served directory.
Without the environment variable, the form still loads. Submitting plausible input then shows an unavailable message without sending an API request. Real API submissions require an active account and consume quota.
3. Screen input and protect the form
The example accepts a single string of at most 80 bytes, normalizes ordinary spaces and letter case, and checks a basic character pattern. These checks reject obviously unsuitable input cheaply. They do not calculate a checksum or establish that an IBAN is valid; the backend still needs the API result.
A random token stored in the session is included in a hidden field and compared on submission. The server rejects a mismatched token before calling the API. Each session also has a three-second submission cooldown. That helps with repeated clicks, but users can create new sessions, so it is not a production rate limit.
Every value inserted into HTML is escaped with htmlspecialchars, including the input shown after an error. The implementation uses explicit quote escaping and UTF-8 substitution as described in the PHP escaping reference. Browser responses use Cache-Control: no-store. Session cookies use HttpOnly and SameSite; the PHP session documentation explains the configuration options.
4. Make one bounded API request
The client reads IBAN_TEST_API_TOKEN on the server and sends an Authorization: Bearer header. Its request body contains just the normalized IBAN:
{"iban":"DE89370400440532013000"}
The download fixes the destination in code. Form input cannot select a host. TLS certificate and hostname verification stay enabled; redirects are disabled. The connection timeout is three seconds and the overall transfer timeout is eight seconds. A response larger than 64 KiB aborts the transfer. See the PHP cURL reference for the option interface.
There is no automatic retry. A timeout can leave uncertainty about whether the provider processed a request, and repeating calls can consume more quota. The page presents a temporary failure instead. If your application later adds retries, define a bounded policy that accounts for both latency and quota.
5. Show the right outcome
Check both transport success and the response fields. For this endpoint, the example handles three outcomes according to the documented result codes:
- Valid: HTTP 200, integer
code: 2100and booleanerror: falsemust all be present. - Invalid bank data: a well-formed HTTP 200 response with code
3100,3101or3102and booleanerror: trueasks the user to correct the entry. Contradictoryerror: falseresponses are treated as unavailable. - Unavailable: authentication or quota problems, other HTTP statuses, timeouts, unknown codes and malformed JSON show an operational error.
An unavailable check must not tell a customer their IBAN is invalid. The sample supplies its own messages rather than displaying raw provider text. A valid result confirms formal validation; it does not prove account ownership, account existence or payment success.
6. Prepare your application for deployment
Before exposing the form publicly, require application authorization and enforce a shared quota budget across users, sessions and application instances. For guest checkout, tie access to a server-authorized checkout session and add abuse controls. The session cooldown and CSRF check alone do not protect your paid quota.
Use HTTPS, secure cookies, a production PHP server and server-side request-body limits. Configure trusted proxy handling explicitly if TLS terminates upstream. Supply secrets through your hosting environment; PHP-FPM may need explicit environment configuration. Exclude tokens, IBAN request bodies and sensitive exception details from logs and monitoring. Never publish a diagnostic page that dumps the environment.
The included tests use a fake transport and dummy credentials to exercise valid, invalid and unavailable results, CSRF rejection, escaping and cooldown behavior. They simulate a failed transfer to check timeout handling without waiting on the network. They do not constitute an authenticated live API test. Use those tests when adapting the example, then verify your own staging configuration before enabling real customer submissions.
