Skip to content

HTTP API Authentication

Every HTTP request to https://openapi.abetterchoice.ai/abc/... carries three headers that prove the caller has a valid API token. The signature is computed once per request from the token, the key name, and the current Unix timestamp.

Headers

HeaderDescription
X-AkThe name of the API key you created in Settings → SDK&Key. Not the token itself.
X-EtThe current Unix timestamp in seconds, e.g. 1748520000 for 2025-05-29 11:20:00 UTC.
X-EsMD5 hex string of the concatenation token + ak + et — the signature.

The token never appears in the request. Only the key name (ak), the timestamp (et), and the signature (es) travel over the wire, so a leaked request line cannot be replayed once the token is rotated.

Computing the signature

signature = lowercase_hex(MD5(token || ak || et))

Where:

  • token is the value from the Token column in Settings → SDK&Key.
  • ak is the value from the Name column for the same row.
  • et is the current Unix timestamp in seconds.

Bash

bash
ak="your_secret_key_name"
token="your_api_token"
et=$(date +%s)
signature=$(echo -n "${token}${ak}${et}" | md5)
echo "X-Ak: $ak"
echo "X-Et: $et"
echo "X-Es: $signature"

macOS uses md5; Linux uses md5sum | awk '{print $1}'. Both produce the same hex string.

Python

python
import hashlib, time

ak    = "your_secret_key_name"
token = "your_api_token"
et    = str(int(time.time()))
sig   = hashlib.md5(f"{token}{ak}{et}".encode()).hexdigest()

headers = { "X-Ak": ak, "X-Et": et, "X-Es": sig }

Go

go
import (
    "crypto/md5"
    "encoding/hex"
    "fmt"
    "time"
)

ak    := "your_secret_key_name"
token := "your_api_token"
et    := fmt.Sprintf("%d", time.Now().Unix())
sum   := md5.Sum([]byte(token + ak + et))
sig   := hex.EncodeToString(sum[:])

Node.js

javascript
const crypto = require("node:crypto");

const ak    = "your_secret_key_name";
const token = "your_api_token";
const et    = Math.floor(Date.now() / 1000).toString();
const sig   = crypto.createHash("md5").update(token + ak + et).digest("hex");

Putting it together

bash
curl -X POST 'https://openapi.abetterchoice.ai/abc/get_experiments' \
  -H "Content-Type: application/json" \
  -H "X-Ak: $ak" -H "X-Et: $et" -H "X-Es: $signature" \
  -d '{"project_id":"6666","unit_id":"user_id_1"}'

If the headers are valid, you get ret_code: 100 and the data — see Endpoints.

Common authentication errors

SymptomLikely cause
ret_code: 101 (no permission)X-Ak does not match a key in this project, or the key is Deactivated.
Stale-timestamp rejectionServer clock and your machine differ by more than the allowed window. Sync via NTP and re-sign.
Signature mismatchConcatenation order is wrong (must be token + ak + et), or you signed the wrong token.

Security best practices

  • Never commit a token to a repository. Pair every key with a secret manager (Vault, AWS Secrets Manager, Tencent Cloud SSM, etc.) and inject at deploy time.
  • One key per consumerserver_prod, server_staging, http_batch. You can deactivate exactly the consumer that leaked without breaking the rest of the fleet.
  • Rotate before, then deactivate. Deactivation is immediate; new keys take effect immediately. Roll out the new key first, drain traffic, then deactivate the old one. Full procedure on API keys.
  • Treat the timestamp like a freshness token — sign and send each request from the calling process, do not pre-compute signatures and ship them around.