Authentication

The CheckYout Partner API uses two authentication mechanisms: an API key for your requests to CheckYout, and a webhook secret to verify the events CheckYout sends to you.

API key

The API key authenticates your requests to the CheckYout API (e.g. POST /api/v1/notify). You create one in the CheckYout dashboard under Settings → API keys.

Format

PropertyValue
Prefixcyo_
LengthPrefix + 32 hexadecimal characters
Examplecyo_a1b2c3d4e5f6...
StorageSHA-256 hashed (clear text shown only once)

Shown only once

The API key is displayed in clear text exactly once on creation. After that, CheckYout only stores its SHA-256 hash. If you lose the key, create a new one.

Usage

Send the API key in the X-API-Key header on every request:

curl -X POST https://checkyout.app/api/v1/notify \
  -H "Content-Type: application/json" \
  -H "X-API-Key: cyo_YourApiKey" \
  -d '{"device_id": "...", "phone": "+41..."}'

Webhook signature

If you configured a webhook secret on the API key, CheckYout signs every webhook with HMAC-SHA256. The signature is sent in theX-CheckYout-Signature header as a hexadecimal string.

HeaderValue
X-CheckYout-SignatureHMAC-SHA256 hex digest of the JSON body using your webhook secret

Verify the signature

Compute the HMAC-SHA256 of the raw request body using your webhook secret and compare it to the value in the header:

const crypto = require('crypto');

function verifySignature(body, secret, signature) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(JSON.stringify(body))
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(expected, 'hex'),
    Buffer.from(signature, 'hex')
  );
}

// Inside your webhook handler:
app.post('/webhooks/checkyout', (req, res) => {
  const signature = req.headers['x-checkyout-signature'];
  const secret = process.env.CHECKYOUT_WEBHOOK_SECRET;

  if (secret && signature) {
    if (!verifySignature(req.body, secret, signature)) {
      return res.status(401).json({ error: 'Invalid signature' });
    }
  }

  // Process the event...
  res.status(200).json({ received: true });
});

Note on the Python signature

CheckYout serialises the body with JSON.stringify() (JavaScript). Make sure your serialisation produces the same format — no extra whitespace. When in doubt, verify against the raw request body rather than re-serialising.

Best practices

  • Store the API key in an environment variable, never in source code.
  • Rotate the key immediately if you suspect compromise.
  • Use timingSafeEqual (or its equivalent) when comparing signatures to prevent timing attacks.
  • Verify the webhook signature before processing the event.
  • Log failed signature checks for your security monitoring.