SellerCenter

Request Signing

Overview

For security reasons, some endpoints require request signing. Endpoints that require it say so in their description, for example Create a Transaction. A signed request proves that it was created by your OAuth application and was not changed or replayed on the way.

Signature Headers

To sign a request, send the following headers together with the usual Authorization: Bearer header:

  • X-Timestamp: Timestamp of the request in UNIX time (seconds)
  • X-Nonce: A random, unique string (max. 40 characters)
  • X-Signature-Algorithm: HMAC-SHA256
  • X-Signature: The calculated signature as a lowercase hexadecimal string

Calculate the Signature

Build the signature content in the format below, then sign it with HMAC-SHA256 using your OAuth application secret.

$httpMethod $requestPathWithQuery
timestamp=$timestamp
nonce=$nonce
body_hash=sha256($body)
  • $httpMethod is the uppercase HTTP method, for example GET or POST
  • $requestPathWithQuery is the request path, followed by ? and the query string when the request has query parameters
  • body_hash is the SHA-256 hash of the request body as a lowercase hexadecimal string. Leave it empty when the request has no body, for example for GET requests

Note:

  • Sort query parameters by name and encode them according to RFC 3986 (a space is encoded as %20, not +)
  • The lines are separated by a single line feed (\n) and there is no trailing line feed

Example

Imagine the following request and settings:

  • GET https://example.com/my/path?foo=bar&zzz=second+parameter
  • Timestamp is 1234567890 (Feb 13 2009)
  • Nonce is 9b95be45f403af9c0039e08bee85f409611fa1b2
  • Application secret is my_key_123456789012345678901234567890123

The resulting signature content is:

GET /my/path?foo=bar&zzz=second%20parameter
timestamp=1234567890
nonce=9b95be45f403af9c0039e08bee85f409611fa1b2
body_hash=

The calculated signature (using the above secret) is 88810379e74af556c15fad9c8fc9fc1756b000d3915df597b69056af0f3ff004.

If the same settings are used to send POST https://example.com/my/path with body {"foo":"bar","zzz":"second parameter"}, the body_hash is 40c9aa2af101ea84a90c0eb711d502277a6ca1bff772917a8b772f0efc0b1cde and the signature content is:

POST /my/path
timestamp=1234567890
nonce=9b95be45f403af9c0039e08bee85f409611fa1b2
body_hash=40c9aa2af101ea84a90c0eb711d502277a6ca1bff772917a8b772f0efc0b1cde

The calculated signature is f0d36077e97b2f644d960cd60b1875c7dabfc1630d52c7538e5bd1b0012a75be.

The following Python snippet reproduces the GET example:

import hashlib
import hmac

app_secret = "my_key_123456789012345678901234567890123"
body = ""  # raw request body, empty for GET requests

body_hash = hashlib.sha256(body.encode()).hexdigest() if body else ""
content = "\n".join([
    "GET /my/path?foo=bar&zzz=second%20parameter",
    "timestamp=1234567890",
    "nonce=9b95be45f403af9c0039e08bee85f409611fa1b2",
    f"body_hash={body_hash}",
])

signature = hmac.new(app_secret.encode(), content.encode(), hashlib.sha256).hexdigest()
print(signature)  # 88810379e74af556c15fad9c8fc9fc1756b000d3915df597b69056af0f3ff004

Validation Rules

Important:

  • The access token must be issued to an OAuth application (see Authorization), because the signature is checked with that application's secret
  • X-Timestamp must be within 10 minutes of the server time
  • X-Nonce must be unique for your OAuth application. Never reuse a nonce, not even when you retry a request
  • Hash the exact body bytes you send. Re-serializing the JSON after signing changes the hash

If the validation fails, the API returns HTTP status 412 Precondition Failed with a message in the format Request signing failed. Reason: <reason>, for example Request signing failed. Reason: Nonce is not unique.

On this page