Documentation Index
Fetch the complete documentation index at: https://docs.bloobank.com/llms.txt
Use this file to discover all available pages before exploring further.
Sending authenticated requests
After generating your ECDSA key pair and registering the public key with Bloobank, you receive anAccess Key.
That Access Key, together with the cryptographic signature of the request, must be sent in the headers of every authenticated API call.
Each authenticated request must include the following headers:
| Header | Required | Description |
|---|---|---|
X-Access-Key | Yes | Credential identifier provided by Bloobank after registering the public key. |
X-Access-Timestamp | Yes | Unix timestamp in milliseconds, UTC. Must represent the moment the request is sent. |
X-Access-Request-Id | Yes | Unique request identifier. UUID v4 is recommended. Must be regenerated on every attempt, including retries. |
X-Access-Signature | Yes | ECDSA signature of the request, Base64-encoded. |
How to build the headers
To authenticate a request, follow the steps below:Access Key
The Example:
Access Key identifies the credential used in the request. Send it in the X-Access-Key header.5kUVpgTHq3N2kBfAZEPXvv2v2JQartRcPtAh27KiwzkGTimestamp
Send the Unix time in milliseconds (UTC) in the Example:
X-Access-Timestamp header.1715097600000The timestamp prevents replay attacks. Requests outside the tolerance window are rejected with
TIMESTAMP_SKEW_EXCEEDED. Keep your servers synchronized via NTP.Request ID
Each request must have a unique identifier (UUID v4) in the Example:
X-Access-Request-Id header.f47ac10b-58cc-4372-a567-0e02b2c3d479 Request body hash
Compute the SHA-256 of the raw request body in lowercase hex.Example body:For requests with no body, use the SHA-256 of an empty string:
Canonical string
Build the canonical string by joining the fields with
Example:
::| Field | Description |
|---|---|
accessKey | Same value as the X-Access-Key header. |
requestId | Same value as the X-Access-Request-Id header. |
timestamp | Same value as the X-Access-Timestamp header. |
METHOD | HTTP method in uppercase: GET, POST, PUT, or DELETE. |
pathname | URL path, without the query string. |
bodySha256Hex | SHA-256 of the raw body in lowercase hex. |
Full example
After completing all steps, the final request should look something like this:Security best practices
Never commit your private key
Never commit your private key
Add
*.pem and .env to .gitignore from the start. Use a secret manager in production and direnv / dotenv locally.Use separate keys per environment
Use separate keys per environment
Staging and production must use different key pairs. Never reuse a staging key
in production.
Rotate keys periodically
Rotate keys periodically
Generate a new key pair every 6–12 months, or immediately if you suspect a
compromise. Send the new public key to the Bloobank integration support team,
switch traffic after receiving the new
X-Access-Key, and request revocation
of the old key.Use a secret manager
Use a secret manager
Store the private key in environment variables or a secrets manager such as
AWS Secrets Manager, HashiCorp Vault, or Doppler. Never hard-code it in
source.
Keep NTP active
Keep NTP active
The
X-Access-Timestamp header must be within the server’s tolerance window. Clock drift of a few minutes causes 401 errors. Run chronyd or ntpd on your servers.Common authentication errors
Reusing X-Access-Request-Id on retries
Reusing X-Access-Request-Id on retries
Every attempt — including retries — must use a new UUID. Reusing the same ID returns
REPLAY_DETECTED.Sending the timestamp in seconds instead of milliseconds
Sending the timestamp in seconds instead of milliseconds
The timestamp must be in milliseconds (13 digits in 2026).
1715097600
(10 digits) is in seconds and will be rejected.Including the query string in the pathname
Including the query string in the pathname
The
pathname field must not contain the query string. Use /v1/pix-in, not
/v1/pix-in?startDate=2026-05-01.Signing a different body than the one sent
Signing a different body than the one sent
Always compute the hash and sign the exact bytes that will be transmitted.
Re-serializing JSON with different field order or whitespace produces a
different hash and causes
SIGNATURE_INVALID.High-S signature
High-S signature
Enable low-S normalization in your library (
lowS, canonical, or
normalize_s). High-S signatures return SIGNATURE_INVALID.Accidentally using URL-safe Base64
Accidentally using URL-safe Base64
The signature must be encoded as standard Base64 (RFC 4648), not URL-safe Base64. Check that your library is not using
- and _ instead of + and /.