Skip to main content

Authentication

Every client is configured with one explicit Application ID + API version pair. Merchant API v1 keeps the legacy exact-body SHA512 contract. Merchant API v2 uses a domain-separated HMAC-SHA512 contract with mandatory timestamp/nonce replay protection. The server never chooses a default or falls back between versions.

Obtaining Credentials

API credentials and merchant accounts are created by the 123hub team during onboarding. Self-registration is not available.
To obtain your credentials:
  1. Contact your 123hub account manager
  2. Or email support@123hub.pro
Once your account is set up, you can view your credentials in the Merchant Dashboard under Settings > API Keys. You will receive:
Keep your secret_key secure. Never expose it in client-side code, public repositories, or browser requests. If compromised, rotate it immediately from the dashboard.

Authentication Headers

Every request to POST /public/api/multihub/v1 must include the first two headers below. For that endpoint the replay headers are optional, but when used they must be sent together: For POST /public/api/multihub/v2, send all four headers below: The v2 request canonical payload has no trailing newline:
Compute X-Data-Signature = HMAC-SHA512(secretKey, canonicalPayload). The path is the fixed literal shown above. Redis replay storage is mandatory for v2; the request fails closed if the nonce cannot be reserved. Do not retry v2 as v1. Successful v2 responses use X-Data-Signature over:

How Signing Works

1

Prepare the request body

Serialize your request body as a JSON string. This is the exact string that will be sent as the HTTP body.
2

Compute the hash

Concatenate the JSON string with your secret_key (no separator), then compute the SHA512 hash of the result. Output as a lowercase hex string. hash = SHA512(jsonBody + secretKey)
3

Send the request

Send the two required headers. You may also include timestamp and nonce as a pair, as shown below. Webhook resend also accepts the two-header legacy mode; when you send both replay headers, the route-bound signing rules in Webhooks apply.
The JSON string you hash must be byte-for-byte identical to the JSON string sent as the HTTP body. If you use compact serialization (e.g., json.dumps(body, separators=(',',':')) in Python), you must send that exact compact string as the request body. Differences in whitespace, key ordering, or formatting between the hashed string and the sent body will cause error 3000 (Authentication error).

Code Examples

Verifying API Response Signatures

Successful API responses include X-Data-Hash. Verify it with the same merchant API secret:
Use the raw response body bytes exactly as received. This check protects your integration from tampered responses and should be performed before trusting payment identifiers, balances, or status values.

Verifying Webhook Signatures

When 123hub sends webhook notifications to your server, the request includes an X-Data-Hash header. New deliveries also include replay-protection metadata in X-Webhook-Id, X-Webhook-Timestamp, X-Webhook-Nonce, X-Webhook-Signature-V2, and X-Webhook-Signature-V3. Prefer X-Webhook-Signature-V3 when present, and fall back to V2 or X-Data-Hash only for legacy deliveries. X-Webhook-Signature-V3 is HMAC-SHA512(timestamp.nonce.webhookId.rawBody, webhook secret). X-Data-Hash remains SHA512(webhookBody + webhook secret). Webhook create/rotation reveals a dedicated webhook-only secret once. Store it separately from the API credential; rotating one does not rotate the other. Historical API-compatible webhook rows are blocked until explicit webhook secret rotation. For a callback auto-created through params.payment.webhook_url, derive the lowercase webhook secret with HMAC-SHA256(apiSecret, "quadpay:merchant-webhook-signing:v1"), using the exact API secret that authenticated that payment create. Test and production keys do not cross; the resulting callback destination is scoped to that payment.
Always verify webhook signatures before processing the payload. Use a constant-time comparison function (like hash_equals in PHP or crypto.timingSafeEqual in Node.js) to prevent timing attacks.

Test Mode vs Production

Test and production requests use the same API endpoint and the same authentication mechanism. The environment is determined by which credentials you use.
  • Test credentials identify an account-specific test environment and routes confirmed during onboarding
  • Production credentials create real transactions with actual money movement
  • Credentials whose environment does not match the merchant are rejected. Test payments select sandbox provider credentials only and never fall back to a production provider credential or endpoint.
  • Webhooks are delivered in both environments for testing integrations
  • All API responses follow the same format in both environments

Rate Limits

API requests may be rate-limited to ensure fair usage. The public public API controller is exempt from the gateway default IP throttler, but authenticated applications have protective per-method buckets for payment.in, payment.out, payment.status, and balance.get. When a rate limit is applied, it is counted per authenticated merchant/application context and method.
If you exceed an applied limit, the response returns HTTP 429 with the standard API error envelope and Retry-After-* headers. Retry with backoff or contact support if you need a higher production throughput profile.

Error Responses

Authentication errors are returned in the standard response envelope with HTTP 400. Credential policy or merchant-ownership denials return HTTP 403 with code 3008. An enforced credential daily-request limit returns HTTP 429 with code 3009; its counter resets at UTC day rollover. DTO validation failures, including unknown fields rejected by strict validation, return code 9000 when request validation reaches the DTO layer. During deployments, readiness gating can return a non-envelope HTTP 503 before API handling starts.
Invalid Application ID
Invalid Hash Signature

Best Practices

Use Environment Variables

Store your application_id and secret_key in environment variables, never in source code

Rotate Keys Regularly

Regenerate your secret key periodically from the dashboard for enhanced security

Verify Webhooks

Always verify the X-Data-Hash header on incoming webhooks before processing

Monitor Usage

Track API usage in the dashboard to detect anomalies and stay within rate limits