Skip to content

Authentication

2. Base URL

Environment Base URL
Production https://api.360cuzdan.com

A separate test (UAT) URL, if available for your integration, is shared at onboarding. Examples below use the production base URL.


3. Credentials

Value Description
API Key Sent in the X-API-Key header. Identifies your account.
Secret Key Used to sign requests and to verify the callback hashcode. Never expose it client-side.

The secret key is shared once at creation. If lost, it must be regenerated (the old one stops working).


4. Authentication (HMAC-SHA256)

Every request to /paymentapi/v1/* requires these headers:

Header Description Constraint
X-API-Key Your API key Must be active
X-Signature HMAC-SHA256 signature Hex (lowercase)
X-Timestamp Unix timestamp (seconds) Within ±5 minutes of server time
X-Nonce Per-request unique value 8–64 chars, never reused
X-Callback-URL Per-transaction callback override Optional — must point to the same scheme + host (+ port) as the webhook URL registered on your account
Content-Type application/json

X-Callback-URL restriction: the header is only accepted when it targets the same scheme + host (+ port) as your registered webhook URL — you can change the path, not the destination. A header pointing anywhere else (or sent while no webhook is registered on your account) is rejected with 400 X-Callback-URL must match the firm's registered webhook host. If no callback URL can be resolved at all, the request fails with 400 Callback URL not configured on provider.

Platform integrations: if your payment platform (e.g. a turnkey/aggregator provider) has a central callback URL registered with Cuzdan360, all results are delivered there — this header and your account webhook are not used. See section 6.

Signature

Message to sign (lines joined with literal \n newlines):

{HTTP_METHOD}\n{PATH}\n{BODY}\n{TIMESTAMP}\n{NONCE}
  • HTTP_METHOD: POST or GET (uppercase)
  • PATH: e.g. /paymentapi/v1/deposits (path without query string)
  • BODY: the raw JSON body (sign the exact bytes you send); for GET requests with no body, an empty string — the message then contains an empty BODY line
  • TIMESTAMP, NONCE: same values as the headers
X-Signature = HMAC_SHA256(secret_key, message)  →  hex

The path is part of the signature. Sign the full versioned path, including the /paymentapi/v1 prefix. Signing a bare /deposits, or a path from the previous unversioned contract, produces a different digest and the request is rejected with 401 Invalid signature.

Example (bash)

API_KEY="<api-key>"
SECRET_KEY="<secret-key>"
TIMESTAMP=$(date +%s)
NONCE=$(openssl rand -hex 16)
BODY='{"amount":"1000","bank_code":"1","first_name": "Test","last_name": "User","username": "testuser","user_id":"user001","reference":"TX-DEP-001","method":"fast"}'

MESSAGE="POST\n/paymentapi/v1/deposits\n${BODY}\n${TIMESTAMP}\n${NONCE}"
SIGNATURE=$(printf "%b" "${MESSAGE}" | openssl dgst -sha256 -hmac "${SECRET_KEY}" | awk '{print $2}')

curl -X POST "https://api.360cuzdan.com/paymentapi/v1/deposits" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: ${API_KEY}" \
  -H "X-Signature: ${SIGNATURE}" \
  -H "X-Timestamp: ${TIMESTAMP}" \
  -H "X-Nonce: ${NONCE}" \
  -H "X-Callback-URL: https://yoursite.com/cuzdan360/callback" \
  -d "${BODY}"

Common mistake: the BODY you sign and the body you send must be byte-identical. Do not re-serialize the JSON — sign and send the same string.

Complete client implementations (PHP, Node.js, Python) are in section 10.