Signing Requests

To sign multipart/form-data requests, see the section Signing Multipart Requests.

All requests to the Network and Management APIs must be signed and have a valid signature passed in the X-Signature header. To generate the signature:

  1. Construct the following string: {method}\n{path}\n{headers}\n{bodyDigest}, where:

    • {method} is the HTTP method, in uppercase.

    • {path} is the remainder of the URL following the host, including the query string (if present).

    • {headers} is the concatenation of the following headers (if present) in the form {lowercase(name)}:{strip(value)}\n:

      • Accept
      • Authorization
      • Content-Type
      • Host
    • {bodyDigest} is the lowercased, hexadecimal representation of the SHA256 digest of the bytes of the request body (hashing an empty string if there is no body).

  2. Create an HMAC-SHA256 cryptographic hash where the text to hash is the string you created in step 1, and the secret is the secret value associated with the API key being used to make the request.

  3. Set the X-Signature header to V1 {signature} where:

    • {signature} is the signature obtained in step 2 in hexadecimal, lowercased.

    Instead of computing a real signature in Sandbox, you can use a magic header value: X-Signature: sandbox:skip-signature-check

  4. Set an Authorization header of Client {CLIENT_ID} {KEY_ID} where:

    • {CLIENT_ID} is the client ID value obtained from Cash App
    • {KEY_ID} is the Cash App identifier for the API key used to generate the signature in step 2
1// Example request
2// curl --request GET \
3// --url 'https://sandbox.api.cash.app/network/v1/payments?limit=50' \
4// --header 'accept:application/json' \
5// --header 'Authorization:Client {CLIENT_ID} {CLIENT_KEY}' \
6// --header 'content-type:application/json' \
7// --header 'host:sandbox.api.cash.app' \
8// --header 'X-Region: PDX' \
9// --header 'X-Signature: {X-Signature}'
10
11//Loading the crypto module in node.js
12let crypto = require('crypto');
13
14// API Credentials
15let client_id = '';
16let api_key = '';
17let api_secret = '';
18let path = '/network/v1/payments?limit=50';
19let host = 'sandbox.api.cash.app';
20
21// STEP 1: construct the following string: {method}\n{path}\n{headers}\n{bodyDigest}
22let method = 'GET';
23let headers = 'accept:application/json' + '\nauthorization:Client ' + client_id + ' ' + api_key + '\ncontent-type:application/json' + '\nhost:' + host;
24let body_digest = crypto.createHash('sha256').update('').digest('hex');
25let raw_signature = method + '\n' + path + '\n' + headers + '\n' + body_digest
26
27// STEP 2: create an HMAC-SHA256 crypto hash with API secret.
28let hashed_signature = crypto.createHmac('sha256', api_secret).update(raw_signature).digest('hex');
29
30// STEP 3: X-Signature header should be set to the following schema "V1 {signature}
31let final_signature = 'V1 ' + hashed_signature;
32
33//Printing the output on the console
34console.log("X-Signature: " + final_signature);

Webhook signatures: Webhook deliveries also contain an X-Signature header that is computed using the same process. This allows webhooks delivered by Cash App to be validated by computing the signature from the request payload and verifying that it matches the X-Signature header

Signing Multipart Requests

To sign requests using the multipart/form-data content type, use this modified signing algorithm:

  1. Construct the following string: {method}\n{path}\n{headers}\n{bodyDigest}, where:

    • {method} is the HTTP method, in uppercase.

    • {path} is the remainder of the URL following the host, including the query string (if present).

    • {headers} is the concatenation of the following headers (if present) in the form {lowercase(name)}:{strip(value)}\n:

      • Accept
      • Authorization
      • Content-Type (this should be multipart/form-data with no other parameters)
      • Host
    • {bodyDigest} is the lowercased, hexadecimal representation of the SHA256 digest of the bytes of the request object specified in the request body.

  2. Create an HMAC-SHA256 cryptographic hash where the text to hash is the string you created in step 1, and the secret is the secret value associated with the API key being used to make the request.

  3. Append a text/plain object named signature to the request body, containing the value V1 {signature} where {signature} is the value obtained in step 2 in hexademical and lowercased.

    This signature will take precedence over any X-Signature header present in the request.

    Instead of computing a real signature in Sandbox, you can use a magic value: sandbox:skip-signature-check