Request Signing Quickstart

Set up and test request signing in your sandbox account.

Request signing adds an additional layer of security to every request you send to Paxos, and can help protect your account should your Paxos API Client ID and Secret become compromised. Once request signing is enabled on your account, Paxos rejects all unsigned requests to authenticated endpoints.

  • Never share your private keys with anyone. Especially for production deployments. Using an HSM, secrets manager, or key-management service may provide an additional layer of protection.

Before You Begin

  • Ensure you have an active individual (retail) sandbox account. Follow the steps in this guide.
  • Have your sandbox API Client ID and Secret available to construct the payload.
  • Install the JOSE/JWS library in the language of your choice. In this guide, we’ll use the PyJWT[crypto] library to generate the signature.
  • If you need to use the  EdDSA (ed25519) algorithm when generating key pairs, install OpenSSL 3 using the package manager of your choice. Older versions of OpenSSL do not support the EdDSA (ed25519) algorithm. In this guide, we’ll be using the more common ES256 algorithm.

Generate Key Pair

Generate keys using either the ES256 or EdDSA (ed25519) algorithm. ES256 is widely supported on most platforms, including Amazon and Google.

In the terminal, ensure the correct version of OpenSSL is installed:

$ openssl version

If you see command not found: openssl in the output, ensure OpenSSL is properly installed and then try again in a new shell.

To generate a new ES256 private key in the current directory, enter the following in the terminal:

$ openssl ecparam -name prime256v1 -genkey -noout -out my-private-ec.pem

Next, generate the public key in the same directory:

$ openssl ec -in my-private-ec.pem -pubout > my-public-ec.pem

The output should be something similar to the following:

read EC key
writing EC key

The process for EdDSA (ed25519) keys is similar:

$ openssl genpkey -algorithm ed25519 -outform PEM -out my-private-key.pem

If the command outputs Algorithm ed25519 not found ensure you’ve installed OpenSSL 3 before generating your private key in a new shell.

$ openssl pkey -in my-private-key.pem -pubout > my-public-key.pem
  • Properly store and protect your private key. Never share your private key with anyone.

Add Public Key to Your Paxos Account

  1. Sign in to your sandbox account and go to Settings > API Management.
  2. Select the API key for you want to enable signing for and ensure you assign appropriate scope. See this guide if you need to make changes to the API Key and scope.
  3. Scroll down to Danger Zone > Enable Request Signing, click on the lock icon to unlock the feature, then turn on request signing using the slider and "Update Credentials" to save the change!
  4. Then use Add Key to add your public key.
    NOTE: If you get an Internal Server Error message when adding a key, ensure Enable Request Signing is turned on (see the previous step) and try adding the key again. Once the key is added, you can then lock adding keys.
  5. Click "Update Credentials".
  6. Hold the pointer over the key and copy the ID. You’ll need both the Key ID (kid) and algorithm (alg) when generating the signed request.
  7. Ensure you turn on request signing before sending any signed requests.

Generate Signed Request

In this guide, we use the PyJWT[crypto] library to generate the signature. Whether you follow along with our Python3 library or use a different JOSE/JWS, the process is similar.

Construct Header

You will use the header information when generating the signed request.

  • Keys are case sensitive.

The header must include the following information:


The Key ID of the configured Public Key. Retrieved from your Paxos sandbox account.


The algorithm used to generate the Key. The value must be: EdDSA or ES256

Retrieved from your Paxos sandbox account. 

The current timestamp in UNIX time format. Signatures remain valid for 30 minutes after the specified timestamp. 

The API request method (GETPOSTPUTDELETE).

The POST and PUT methods also require the JWS payload in the body bytes. 

The endpoint path, including query parameters.

Putting it together, your header should look similar to the following:

"kid" : "5498f424-78aa-414b-a515-13929e6951db",
"alg" : "ES256",
"" : "1645503272",
"" : "POST",
"" : "/v2/transfer/deposit-addresses"

Because this is a POST method, we’ll include the JWS payload in the body bytes:


You’d do the same thing when using any PUT method.

Generate Signature

Now that we’ve constructed our header, we’ll use the PyJWT[crypto] library to generate the request signature. First, install the library and start a new session:

$ pip3 install "pyjwt[crypto]" && python3

Generate the JWT signature:

>>> import jwt
>>> payload = b'{"profile_id":"42bb1a2e-a68e-44d7-b5f1-59ccc5c13e91","crypto_network":"ETHEREUM"}'
>>> with open('./my-private-ec.pem', 'rb') as f: key =
>>> alg = "ES256" if key.find('BEGIN EC PRIVATE'.encode('ascii')) > 0 else "EdDSA"
>>> headers = {"kid": "5498f424-78aa-414b-a515-13929e6951db", "alg": alg, 
"": "1645503272",
"" : "POST",
"": "/v2/transfer/deposit-addresses"} >>> signature = jwt.api_jws.encode(payload=payload, key=key, headers=headers,algorithm=alg) >>> print(signature) eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IjU0OThmNDI0LTc4YWEtNDE0Yi1hNTE1LTEzO
2fbGlbe8epuiAJFpFziwxhhKHbc7-DaqKMV9MTTARX8VM3d2YSugPEAow >>> exit()

Send Signed Request

Use the signature generated in the previous step to send a signed request to Paxos. First, authenticate with sandbox:

curl \
-F grant_type=client_credentials \
-F client_id=$clientid \
-F client_secret=$secret \
-F scope="transfer:write_deposit_address"

Then send the signed API request:

curl -X POST 
-H "Authorization: Bearer xRGvKetiw_phEDRnx4UgT7SrPJ9eQv-zjZthDGTYlXQ.Zx7o2uJd_Oit
rsddSqfb1CU92rq5lhnOFHo7YtrCvss" -H "Paxos-Signature: eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IjU0OThmNDI0LTc4Y
XWcmpGaf5OiyU0lo2fbGlbe8epuiAJFpFziwxhhKHbc7-DaqKMV9MTTARX8VM3d2YSugPEAow" -d '{"profile_id":"42bb1a2e-a68e-44d7-b5f1-59ccc5c13e91","crypto_network":"ETHEREUM"}'

Next Steps

Was this article helpful?
0 out of 0 found this helpful