Skip to main content

Request Signing

Our API uses JWT-based request signing to authenticate and verify the integrity of your requests. This guide explains how to implement request signing in your applications.

Overview

Each request to our API must include a signed JWT token in the Authorization header. The token contains claims about the request and is signed using your private key with the RS256 algorithm.
1

Prepare credentials

You need two credentials:
  • API Key: Your unique identifier
  • Private Key: Your RSA private key in PEM format
2

Extract URL path

Extract the path and query parameters from the request URL. Do not include the domain or protocol in the signed data.
3

Generate body hash

Calculate a SHA-256 hash of the request body to ensure integrity.
4

Create and sign JWT

Create a JWT with specific claims and sign it with your private key.
5

Add Authorization header

Include the signed JWT in the Authorization header as a Bearer token.

Implementation

Below is a TypeScript implementation that you can use as a reference for other languages:

JWT Payload Structure

The JWT payload must contain the following claims:
string
required
The URL path with query parameters (excluding domain). Example: /v1/resources?filter=active
number
required
Issued at time as a Unix timestamp (seconds since epoch).
number
required
Expiration time as a Unix timestamp. Should be set to iat + 55 seconds.
string
required
Your API key.
string
required
SHA-256 hash of the request body as a hexadecimal string.

Language-Specific Implementations

Testing Your Implementation

You can verify your implementation is working correctly by:
  1. Generating a signed request
  2. Decoding the JWT at jwt.io to check the claims
  3. Making a test request to our API endpoint
Ensure your request body is identical between signature generation and the actual request. Even a single whitespace difference will result in a different hash and signature validation failure.

Common Issues

This typically means:
  • Your private key format is incorrect
  • The body hash doesn’t match the actual request body
  • The JWT has expired (should only be valid for 55 seconds)
Make sure your JWT includes all required claims: uri, iat, exp, sub, and bodyHash.
The uri claim should only include the path and query string, not the domain or protocol.

Security Best Practices

  • Store your private key securely and never expose it in client-side code
  • Generate a new JWT for each request
  • Keep the expiration time short (55 seconds) to prevent replay attacks
  • Implement proper error handling for failed authentication