ZAHLEN

Chapter 3

Authentication


image

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 3 - Authentication


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.


    1. Authentication model

      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.


    2. The X-API-Key header

      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

    1. Example authenticated requests

      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"

}'


    1. Application examples

      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();



image

Server-side only

image

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.

    1. Security recommendations

      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.

    2. Key rotation without downtime

      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.

    3. Authentication and authorization failures

      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()

    1. Authentication readiness checklist

      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.


    2. Chapter summary

      • 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.