Skip to main content
This page describes V1 signing, which sends an API-Nonce header. It’s for existing integrations whose API keys use V1 (nonce) signing. For new integrations, use V2 signing instead. To move an existing integration to V2, see Which version does my key use?.

Authentication parameters

V1 signing uses HMAC. Every request signed with V1 must include the following headers:
  • API-Key HTTP header parameter: your public API key.
  • API-Nonce HTTP header parameter: monotonically increasing integer nonce.
  • API-Sign HTTP header parameter: HMAC-SHA512 signature of the request.

Setting the API-Key parameter

The value for the API-Key HTTP header parameter is your public API key. Create new keys for V2 signing instead, as described in Authentication.

Setting the API-Nonce parameter

Set API-Nonce to an integer greater than the last value you used with the same API key. Use a high-resolution timestamp, such as nanoseconds since the Unix epoch, unless your integration already has a stronger monotonic counter. Don’t use a timer with an arbitrary origin, such as process.hrtime() in Node.js. It resets when the machine restarts, so your next nonce can be lower than the last one you sent.

Setting the API-Sign parameter

The value for the API-Sign HTTP header parameter is an HMAC-SHA512 signature of the request, base64-encoded.

Algorithm steps

  1. Choose a nonce: generate a monotonically increasing integer.
  2. Build the nonce payload: concatenate the nonce and the exact request body bytes.
    • For requests without a body: use the nonce only.
    • For requests with a body: use the exact bytes you send on the wire.
  3. Hash the nonce payload: generate a SHA-256 digest.
  4. Build the message: concatenate the URL path, including query string, and the SHA-256 digest.
  5. Sign: generate HMAC-SHA512 over the message using your base64-decoded secret.
  6. Encode: base64-encode the signature.

Examples

The following code snippets demonstrate how to generate the signature in Python and JavaScript.

Complete request example

Here’s a complete example making an authenticated GET request to list your webhooks. It reads your credentials from PWS_API_KEY and PWS_API_SECRET, and the API base URL from PWS_BASE_URL. Set PWS_BASE_URL to the sandbox or production base URL, listed in Environments.
If you haven’t registered any webhooks yet, the response is an empty list:
An empty list still means your request was authenticated. If the key or signature is wrong, you get 401 Unauthorized instead.

Query parameters in signature

When your request includes query parameters, they must be included in the URL path used for signature generation. Use the exact same path string in both the signature and the request URL. The examples in this section and the next one call account-scoped endpoints. They read the account ID from PWS_ACCOUNT_ID. To find it, see Find your account ID. A user ID won’t work in its place. See Users, accounts, and ownership.

Request body in signature

For requests that send a body (POST, PUT), the body bytes used to compute the signature must match the bytes sent on the wire exactly. Differences in whitespace, key ordering, or encoding will produce a signature mismatch. The recommended pattern is to serialize the body once and reuse the same string for both signing and the HTTP request:

Troubleshooting