Chapter 3
![]()
API key header, example requests, and security recommendations
Audience
Merchants | Developers | Integration Engineers
Zahlen API User Guide v1.0
Source baseline: zahlen_deploy_0616A.tar.gz | June 2026
Chapter purpose |
This chapter explains how merchant applications authenticate to Zahlen, how the X-API-Key header establishes tenant ownership, how to send authenticated requests, and how to protect, rotate, monitor, and revoke credentials safely. |
Learning objectives |
By the end of this chapter, you should be able to add the correct authentication header, distinguish public and administrative access, test credentials safely, implement secure secret handling, and rotate a key without interrupting production traffic. |
Every merchant-facing Zahlen request begins with authenticated context. The API key does more than prove that a caller knows a secret: it resolves the authorized merchant, tenant, and actor context used for ownership checks, quota enforcement, audit records, and response visibility. For that reason, authentication is part of the data-isolation design, not merely a login step.
Core ownership rule |
Do not send tenant_id as a way to select ownership. Zahlen derives tenant ownership from the authenticated API key. A request body, query parameter, or form field must never override that boundary. |
Surface | Typical authentication | Purpose |
Merchant API - /v1/* | X-API-Key | Payment events, retry decisions, retry outcomes, webhooks, and other approved commercial operations. |
Operator HTML - /admin/* | Authenticated browser session | Human administration, monitoring, investigation, and operational action. |
Administrative JSON - /v1/admin/* | Administrative context | Governance, reporting, automation, and enterprise administration. |
Internal workers | Service configuration | Background evaluation, persistence, and dispatch. |
A merchant key should be used only on merchant-facing routes approved for that key. It should not be assumed to grant access to operator pages or administrative JSON endpoints. Authorization remains endpoint-specific even after authentication succeeds.
Authentication and authorization are different
Question | Authentication answers | Authorization answers |
Who is calling? | Which API key was presented and successfully validated? | Is the resolved identity allowed to use this endpoint and resource? |
Whose data is visible? | Which tenant and merchant context belong to the key? | Does the requested object belong to that tenant and fall within the key's permitted scope? |
What happens on failure? | Usually HTTP 401 for missing or invalid credentials. | Usually HTTP 403 for a valid identity that lacks permission. |
Send the merchant API key in the HTTP request header named X-API-Key. Header names are case-insensitive under HTTP, but integrations should use the documented spelling consistently.
X-API-Key: zk_live_REPLACE_ME
Header | Required? | Purpose |
X-API-Key | Yes for merchant-facing authenticated routes | Authenticates the caller and resolves tenant, merchant, and actor context. |
Content-Type: application/json | Yes for JSON request bodies | Tells the server that the body is JSON. |
Accept: application/json | Recommended | Makes the expected response representation explicit. |
Idempotency-Key | Where supported | Identifies one logical write operation so a safe replay can be recognized. |
User-Agent | Recommended | Identifies the calling application and version for diagnostics. |
Where the key belongs
Put the key in an HTTP header, not in the URL, query string, JSON body, or form field.
Send the key only over HTTPS.
Load the key from a secret manager or protected runtime environment variable.
Keep key handling on trusted server-side infrastructure.
Do not expose the key to browser JavaScript, mobile application bundles, public API clients, or shared screenshots.
Never place a key in a URL |
URLs can be captured in browser history, reverse-proxy logs, analytics systems, support tools, and referrer headers. Authentication secrets belong in protected headers. |
Key resolution sequence
1 Receive header The server reads X-API-Key from the request. | 2 Validate secret The submitted value is checked against secure key records. | 3 Resolve context The key maps to tenant, merchant, actor, status, and policy. | 4 Enforce access Endpoint, plan, quota, and ownership checks are applied. | 5 Audit request The request is correlated with key identity and result. |
The examples in this section use fictional hosts, identifiers, and credentials. Replace them with values supplied for your Zahlen environment. Never paste a live key into documentation, source control, terminal recordings, or support tickets.
Health check without merchant authentication
curl -sS https://api.example.com/v1/health \
-H 'Accept: application/json'
A successful health response confirms connectivity and API availability. It does not prove that a merchant API key is valid or authorized for commercial endpoints.
Authenticated payment-event request
curl -sS -X POST https://api.example.com/v1/payment-events \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'X-API-Key: zk_live_REPLACE_ME' \
-d '{
"events": [{
"event_id": "evt_20260616_0001", "decline_code": "51",
"issuer_bin": "411111",
"amount_minor": 2999, "currency": "USD", "attempt_number": 1,
"event_timestamp": "2026-06-16T12:00:00Z"
}]
}'
Authenticated retry-decision request with idempotency
curl -sS -X POST https://api.example.com/v1/_next/retry-decision \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'X-API-Key: zk_live_REPLACE_ME' \
-H 'Idempotency-Key: order-8842-attempt-2' \
-d '{
"attempt_number": 2,
"decline_code": "51",
"issuer_bin": "411111",
"amount_minor": 2999, "currency": "USD"
}'
Python with requests
import os import requests
base_url = os.environ['ZAHLEN_BASE_URL'].rstrip('/') api_key = os.environ['ZAHLEN_API_KEY']
headers = {
'X-API-Key': api_key,
'Content-Type': 'application/json', 'Accept': 'application/json',
'User-Agent': 'merchant-billing/1.0',
}
payload = { 'events': [{
'event_id': 'evt_20260616_0001', 'decline_code': '51',
'amount_minor': 2999, 'currency': 'USD', 'attempt_number': 1,
}]
}
response = requests.post( f'{base_url}/v1/payment-events', headers=headers,
json=payload, timeout=20,
)
response.raise_for_status() result = response.json() print(result['upload_job_id'])
JavaScript on a trusted server
const baseUrl = process.env.ZAHLEN_BASE_URL.replace(/\/$/, ''); const apiKey = process.env.ZAHLEN_API_KEY;
const response = await fetch(`${baseUrl}/v1/_next/retry-decision`, { method: 'POST',
headers: {
'Content-Type': 'application/json', 'Accept': 'application/json',
'X-API-Key': apiKey,
'Idempotency-Key': 'order-8842-attempt-2', 'User-Agent': 'merchant-recovery/1.0'
},
body: JSON.stringify({ attempt_number: 2,
decline_code: '51',
issuer_bin: '411111',
amount_minor: 2999, currency: 'USD'
})
});
if (!response.ok) {
throw new Error(`Zahlen HTTP ${response.status}`);
}
const result = await response.json();
![]()
Server-side only
![]()
The JavaScript example is intended for Node.js or another trusted server runtime. Never put a
production Zahlen API key in frontend JavaScript delivered to a browser.
Treat every API key as a high-value production secret. A valid key can authorize requests, expose tenant-scoped resources, consume quota, create audit activity, and potentially influence payment-recovery operations.
Control | Recommended practice | Why it matters |
Secret storage | Use a managed secret store, encrypted deployment secret, or protected environment variable. | Reduces accidental exposure and centralizes access control. |
Environment separation | Use different keys for development, staging, and production. | Prevents test traffic and compromised non-production systems from reaching production. |
Service separation | Issue independent keys to independent workloads when policy permits. | Limits blast radius and improves attribution. |
Least privilege | Enable only approved endpoints and capabilities. | Reduces damage from misuse. |
Logging | Log key ID or fingerprint, never the complete secret. | Preserves diagnostics without leaking credentials. |
Transport | Require HTTPS and validate certificates. | Protects the key and request data in transit. |
Rotation | Rotate on a schedule and after personnel or system changes. | Reduces long-lived exposure. |
Revocation | Revoke immediately after confirmed compromise. | Stops further authenticated use. |
Monitoring | Alert on authentication spikes, unusual endpoints, geography, or volume. | Detects misuse and integration defects early. |
Do not log secrets
Redact X-API-Key in application, proxy, and observability logs.
Disable verbose HTTP tracing in production unless headers are safely filtered.
Ensure exception reporters and APM agents do not capture authentication headers.
Use a non-secret key ID, last-four display, or approved fingerprint for support correlation.
Scrub copied curl commands before sharing them.
Do not send prohibited payment data
Authentication secures access to Zahlen, but it does not make every payload appropriate. Use merchant-side payment tokens and the minimum evidence needed for decisioning. Do not submit full primary account numbers, CVV values, passwords, raw bank credentials, or secrets inside metadata objects.
A safe rotation overlaps the old and new credentials for a controlled period. Do not revoke the old key before every production instance can authenticate with the replacement.
1 Create replacement Generate a new key in the same approved tenant, merchant, environment, and scope. | 2 Store securely Place the new secret in the secret manager without removing the old one. | 3 Deploy gradually Update services and instances using ordinary release controls. | 4 Verify traffic Confirm successful requests, audit activity, and expected key identity. | 5 Revoke old key Remove the previous key after all callers have migrated. |
Phase | Old key | New key | Operator check |
Before rotation | Active | Not created | Confirm current usage and owners. |
Overlap | Active | Active | Watch traffic move to the new key. |
Cutover complete | Active but unused | Active | Confirm no legitimate calls still use the old key. |
After revocation | Revoked | Active | Alert on any attempted use of the retired key. |
When to rotate immediately
The secret appears in a public or shared repository.
The key is pasted into a ticket, chat, email, document, screenshot, or terminal recording.
A device or service containing the key is compromised.
An employee or vendor with secret access leaves the role.
Authentication activity is inconsistent with expected services, endpoints, volume, or time windows.
The key has exceeded the organization's maximum credential age.
Compromise response |
Do not wait for proof of malicious use when a production key is exposed. Create a replacement, deploy it, revoke the exposed key, review audit records, and preserve incident evidence. |
HTTP status | Likely meaning | Client response |
401 Unauthorized | X-API-Key is missing, malformed, unknown, expired, or revoked. | Check the header, secret source, environment, and key status. Do not retry rapidly. |
403 Forbidden | The key is valid but not permitted for the route, capability, plan, or resource. | Check endpoint authorization, plan, scope, and administrative boundary. |
404 Not Found | The resource does not exist or is not visible in the resolved tenant context. | Verify the tenant-scoped identifier; do not weaken ownership filters. |
409 Conflict | An idempotency key conflicts with a different request or resource state. | Compare the original logical operation and payload. |
429 Too Many Requests | The tenant has reached a rate limit or quota. | Back off, honor Retry-After when present, and preserve idempotency for the same operation. |
Diagnostic sequence
1 Check hostname Verify development, staging, or production base URL. | 2 Check header Confirm X-API-Key is present once and not surrounded by unintended quotes. | 3 Check secret source Confirm the deployed secret version and application configuration. | 4 Check status Verify the key is active, unexpired, and associated with the expected context. | 5 Check authorization Review plan, endpoint policy, audit records, and tenant ownership. |
Fail closed |
A missing tenant context, unresolved key, or failed ownership check should deny access. Never fall back to a default production tenant to make a request succeed. |
Example error-safe client behavior
if response.status_code == 401:
raise RuntimeError('Zahlen authentication failed; check key and environment') elif response.status_code == 403:
raise RuntimeError('Zahlen authorization denied; check route and plan') elif response.status_code == 429:
# Back off. Use Retry-After when provided.
# Reuse the same Idempotency-Key for the same logical operation. schedule_retry_with_jitter(response.headers.get('Retry-After'))
else:
response.raise_for_status()
Check | Ready when |
Environment | The base URL and key belong to the same intended environment. |
Tenant context | The key resolves the approved tenant and merchant. |
Secret storage | The full key exists only in approved protected secret storage. |
Source control | No live key appears in repositories, examples, test snapshots, or documentation. |
Transport | All calls use HTTPS and certificate validation remains enabled. |
Client architecture | Authentication is performed by trusted server-side code. |
Idempotency | Supported write operations use stable logical idempotency keys. |
Logging | Authentication headers are redacted; safe key identity is logged. |
Rotation | A documented overlap-and-revoke procedure exists and has been tested. |
Monitoring | Alerts cover authentication failures, revoked-key use, and unusual traffic. |
Incident response | Owners know how to replace and revoke a compromised key. |
Schedule integrity | Recovery workflows preserve the fixed Day 1, Day 2, Day 6, and Day 16 schedule. |
Merchant-facing Zahlen requests authenticate with the X-API-Key header.
The API key resolves tenant, merchant, and actor context; tenant ownership is not selected by request JSON.
Authentication proves identity, while authorization decides whether that identity may use a route or resource.
Keys belong in protected server-side secret storage and must never appear in URLs, browser code, logs, or shared documents.
Use Idempotency-Key where supported for safe replays of one logical write operation.
Rotate keys with overlap, verify the replacement, then revoke the retired credential.
Treat 401, 403, 404, 409, and 429 as different conditions requiring different responses.
Authentication enables access but does not alter Zahlen's fixed Day 1, Day 2, Day 6, and Day 16 retry schedule.
Next chapter |
Chapter 4 - Usage Plans explains the FREE, PROFESSIONAL, and ENTERPRISE plan concepts and how clients should interpret plan-assigned capabilities without hard-coding deployment-specific policy. |