Verifying Webhook Signatures

When Orbital sends a webhook (an HTTP POST to your notifyUrl), it also attaches a digital signature in the headers. That signature is generated using Orbital’s private key, and you can verify it using Orbital’s public key.

If the signature matches, you know two things:

  • The webhook really came from Orbital (authenticity).
  • The body hasn’t been changed in transit (integrity).

If it doesn't match, reject the webhook because the request may have been forged and it isn't from Orbital.

How webhook signing works

  • Orbital computes an RSA-SHA256 signature of the raw JSON request body.
  • The signature is included in the X-Orbital-Signature header (Base64 encoded).
  • You verify the signature against Orbital’s public key.
  • If verification fails, you must reject the webhook and ignore its contents.

Orbital Public Key

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3sQxyMwmDXQm3mumy345
E4NZID1guNsOYSMC7WDRbwpbCSnLDSXRZTiImdONjOTeH7UZtfF1G7YY78LrxYUS
x0dnqpAMfCgfJwt/JPMIJcfg5be2WaKMjC5uXK9Shlp9JUSFfV93YChcTkOTyv2j
CmQ+KU1P3UafpmKjCc5BwR9AIut6AGc6xtIfqb9VRa1hWGTS6XLuZQlH2Q0qYYnY
9zJVFPuBucV5t3w6brV8klpYs4OhRRKBn+2FI8bSltoreoTOdKpN5ot7mKK8uzaO
vjrHPUJbkwc0r6KUKTVqyBYz5GUAzt2ld6HYUP1g9zD6MGNOM/jEShThmDKSVm8G
DQIDAQAB
-----END PUBLIC KEY-----

Verification steps

  1. Receive the webhook body: Orbital sends your server a webhook. The request contains:
  • Body (JSON ) - the actual event data, E.g
 {
  "id": "d3da3a8d-1e4b-4a24-a2e5-1da62934c169",
  "externalId": "ORBITAL-CUSTOMER-REFERENCE-0001",
  "status": "initiated",
  "type": "deposit",
  "updatedAt": "2025-09-03T09:29:31.946Z",
  "event": "crypto_payment_status_updated"
}
  • Headers - metadata attached to the request, including the signature
Content-Type: application/json
X-Orbital-Signature: AbCdEfGhIj... (base64 string)
X-Orbital-Timestamp: 2025-09-02T12:00:00Z
  1. Verify Signature with Orbital Public key. : This is the Orbital public key that you can use to check and verify if the signature is real. See full key above.
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQE...
-----END PUBLIC KEY-----
  1. Set up RSA-SHA256: You need to set up your crytp libray to use this algorithm. This is crucial because for the verification to succeed, you must use the exact same algorithm that Orbital used to create the signature.
  2. Check the match: Give the library the JSON body, the signature, and the public key.
  • If it matches → the webhook is real, go ahead and process it.
  • If it doesn’t match → reject it, don’t trust the data.

Example verification code

TypeScript (Node.js)

const crypto = require('crypto');

const data = {
  "id": "d3da3a8d-1e4b-4a24-a2e5-1da62934c169",
  "externalId": "ORBITAL-CUSTOMER-REFERENCE-0001",
  "status": "initiated",
  "type": "deposit",
  "updatedAt": "2025-09-03T09:29:31.946Z",
  "event": "crypto_payment_status_updated"
}

const signature =
  'd9dnS7vz4zw6erJdvBDY2w3Yk6VJj+O/51VcJJcBaoYYDZXg8Xt1pGgTwDcDTV+ohxEOY6MmJUX7jgC22KoN7jXbj5WLSAdwyZJPlnjX1btMDneCrr/2K33+fubcggd0ER3hhqHYRA2RjiXv142dcK9IVVDWSzTS00K0zIGyal27gFfgPMOmmB8nvzryME5/d5vZnPWizhpjbnzvZyGSI6CDZ+MovkhmgAvdHfrxdTDMwG5YDrlCcaLcKqOja22vKfHuhtvRpXAdgnOV2qIZOdkspF7KD/MWARsRUermGFcnBLpOgOJo09/SOx4RRz+9d5p9NNEBxkR9UPExwdE8kw==';

const publicKey = `
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3sQxyMwmDXQm3mumy345
E4NZID1guNsOYSMC7WDRbwpbCSnLDSXRZTiImdONjOTeH7UZtfF1G7YY78LrxYUS
x0dnqpAMfCgfJwt/JPMIJcfg5be2WaKMjC5uXK9Shlp9JUSFfV93YChcTkOTyv2j
CmQ+KU1P3UafpmKjCc5BwR9AIut6AGc6xtIfqb9VRa1hWGTS6XLuZQlH2Q0qYYnY
9zJVFPuBucV5t3w6brV8klpYs4OhRRKBn+2FI8bSltoreoTOdKpN5ot7mKK8uzaO
vjrHPUJbkwc0r6KUKTVqyBYz5GUAzt2ld6HYUP1g9zD6MGNOM/jEShThmDKSVm8G
DQIDAQAB
-----END PUBLIC KEY-----
`;


function verifySignature(data, signature, publicKey) {
  const verify = crypto.createVerify('RSA-SHA256');
  const parsedData = JSON.stringify(data);
  verify.update(parsedData);
  verify.end();
  return verify.verify(publicKey, signature, 'base64');
}

const result = verifySignature(data, signature, publicKey);
console.log('Is signature verified?', result);