API request signing
Every B402 API request is signed with RSA-SHA256 using a 1024-bit RSA key pair you own.
- One-time setup (Step 1): generate a key pair and submit the public key during onboarding.
- Per request (Steps 2–3): sign the payload
jsonBody + timestamp, then send the signature plus the timestamp in request headers.
The server validates that the timestamp is within 5 minutes of its current time.
How it works
- You generate a 1024-bit RSA key pair and share the public key during onboarding.
- For each API request, you construct the signing payload:
jsonBody + timestamp. - You sign the payload using SHA256withRSA with your private key.
- The Base64-encoded signature is sent in the
X-Tesla-Signatureheader along with the timestamp (milliseconds) in theX-Tesla-Timestampheader. - B402 verifies the signature using your registered public key and validates that the timestamp is within 5 minutes of the server time.
Step 1 — Generate your RSA key pair (one-time)
Run the following commands. They leave you with two files: private_key.base64 (keep private) and
public_key.base64 (submit during onboarding).
Code
Note: Keep
private_key.base64safe and private — it is used to generate signatures.
Note: Submit
public_key.base64during onboarding — see Apply partner developer account.
Step 2 — Sign each request
The payload to sign is jsonBody + timestamp — the JSON request body concatenated with the
millisecond timestamp string. Encode as UTF-8, sign with SHA256withRSA, then Base64-encode the
signature.
The examples below use body = "{}" because that's the body /supported accepts. For /verify and
/settle the body is a full paymentPayload JSON — see the
V2 Open APIs reference for the exact shape. The
signing logic is the same either way: whatever bytes you send as the request body, concatenate with
the timestamp and sign.
Python
Code
Dep: pip install pycryptodome.
Node.js
Uses the built-in crypto module — no external dependencies.
Code
Java
Code
Step 3 — Set the required headers
| Header | Value | Mandatory |
|---|---|---|
Content-Type | application/json | Yes |
X-Tesla-ClientId | Your clientId (provided by B402 during onboarding) | Yes |
X-Tesla-SignAccessToken | Your accessToken (provided by B402 during onboarding) | Yes |
X-Tesla-Signature | The Base64 signature produced in Step 2 | Yes |
X-Tesla-Timestamp | The millisecond timestamp you concatenated into the payload | Yes |
X-Tesla-Timestamp must equal the exact millisecond value you concatenated into the payload
before signing — the server recomputes jsonBody + X-Tesla-Timestamp to verify. The server rejects
requests whose timestamp is more than 5 minutes off its current time.
Testing with Postman (optional)
1. Environment variables
Create an environment (e.g. Sandbox) in Postman with base_url, client_id, access_token,
private_key. The private_key value should be in PEM form:
Code
2. Signing library
Install postman-util-lib. Add a Postman global
variable pmlib_code and paste the contents of the
bundle.js as its value.
3. Pre-request script
Add the following to your collection or request:
Code
Troubleshooting
- Timestamp must be in milliseconds. A Unix timestamp in seconds will fail signature
verification. The value in
X-Tesla-Timestampmust exactly match the one concatenated into the payload before signing. jsonBodyis the exact UTF-8 bytes of the request body. Serialize your object to a string once, then use the same string for both the request body and the signing payload — re-serializing (with different key ordering or whitespace) produces a different signature.- Private key format.
PRIV_KEY_B64must be the Base64 PKCS#8 DER string produced by Step 1 (private_key.base64). Do not include the-----BEGIN PRIVATE KEY-----PEM wrapper. - 5-minute timestamp window. The server rejects requests whose timestamp is more than 5 minutes off its current time. Check your client clock if signed requests fail intermittently.