Documentation

Spotify WebHooks documentation. This app is still very new, so I'm sure there are some bugs and improvements that need to be made. If you have any questions, please email me at jakewhiteyo@gmail.com

Every webhook we send includes a signature so you can verify it came from us and wasn't tampered with.

The Signature Format

Every webhook includes two headers for verification:

  • x-webhook-timestamp - The Unix timestamp (seconds since epoch) when the webhook was sent
  • x-webhook-signature - The HMAC-SHA256 signature of the webhook
x-webhook-timestamp: 1704067200
x-webhook-signature: sha256=a1b2c3d4e5f6789...

The signature format is: sha256=signature

How to Verify It

Here's the simple process to verify a webhook signature:

  1. Get the timestamp from the x-webhook-timestamp header
  2. Get the signature from the x-webhook-signature header
  3. Create a signed payload by concatenating the timestamp and payload: {timestamp}.{payload}
  4. Create an HMAC-SHA256 hash of the signed payload using your webhook secret
  5. Compare your hash with the signature in the header

Example Code

// Node.js example - verifying a webhook
const crypto = require('crypto');

function verifyWebhook(payload, timestamp, signature, secret) {
  // Extract the signature value (remove 'sha256=' prefix)
  const sigValue = signature.replace('sha256=', '');
  
  // Create the signed payload: timestamp + '.' + payload
  const signedPayload = `${timestamp}.${payload}`;
  
  // Generate HMAC-SHA256 using your secret
  const expectedSig = crypto
    .createHmac('sha256', secret)
    .update(signedPayload)
    .digest('hex');
  
  // Compare signatures (use constant-time comparison in production)
  return expectedSig === sigValue;
}

// Usage in your webhook endpoint
app.post('/webhook', (req, res) => {
  const timestamp = req.headers['x-webhook-timestamp'];
  const signature = req.headers['x-webhook-signature'];
  const payload = JSON.stringify(req.body);
  
  if (!timestamp || !signature) {
    return res.status(401).send('Missing required headers');
  }
  
  if (verifyWebhook(payload, timestamp, signature, process.env.WEBHOOK_SECRET)) {
    // Webhook is authentic, process it
    console.log('Webhook verified successfully');
    res.status(200).send('OK');
  } else {
    // Webhook is invalid
    res.status(401).send('Unauthorized');
  }
});

Important Notes

  • • Always verify signatures before processing webhooks
  • • The signature is created from {timestamp}.{payload}, not just the payload
  • • Your webhook secret is found in your webhook settings
  • • Keep your secret secure and never share it
  • • Use constant-time comparison when comparing signatures in production

Understanding the structure and content of webhook payloads sent by our service.

Payload Structure

All webhook payloads follow a consistent JSON structure:

Content-Type: application/json

Event Types

We currently support the following event types:

  • artist_release - When an artist releases new music

Example Payload

{
  "event": {
    "id": "2617e41f-3f78-405e-82fb-b3f1b5ccef65",
    "subscriptionId": "cme21c0y70073op5j51yxp9ej",
    "type": "artist_release"
  },
  "releases": [
    {
      "id": "9e28a075-b3cd-4c3c-822b-ed745a7b112a",
      "name": "Hey!",
      "type": "single",
      "spotify_id": "6RBPVj54i4cUFK3CSNSQgb",
      "href": "https://api.spotify.com/v1/albums/6RBPVj54i4cUFK3CSNSQgb",
      "release_date": "2025-07-22",
      "album_type": "single",
      "images": [
        {
          "url": "https://i.scdn.co/image/ab67616d0000b2736fdf99a965ca25819aadcbc6",
          "height": 640,
          "width": 640
        },
        {
          "url": "https://i.scdn.co/image/ab67616d00001e026fdf99a965ca25819aadcbc6",
          "height": 300,
          "width": 300
        },
        {
          "url": "https://i.scdn.co/image/ab67616d000048516fdf99a965ca25819aadcbc6",
          "height": 64,
          "width": 64
        }
      ],
      "artists": [
        {
          "external_urls": {
            "spotify": "https://open.spotify.com/artist/0pkLgeB9j465x1QB2kRoy4"
          },
          "href": "https://api.spotify.com/v1/artists/0pkLgeB9j465x1QB2kRoy4",
          "id": "0pkLgeB9j465x1QB2kRoy4",
          "name": "HAAi",
          "type": "artist",
          "uri": "spotify:artist:0pkLgeB9j465x1QB2kRoy4"
        }
      ],
      "total_tracks": 4
    },
    {
      "id": "47028c08-66a9-426c-b415-12e1e45e4bc8",
      "name": "DJ-Kicks: HAAi",
      "type": "album",
      "spotify_id": "5f7wLlgF33y9CUibAk3a5z",
      "href": "https://api.spotify.com/v1/albums/5f7wLlgF33y9CUibAk3a5z",
      "release_date": "2023-11-10",
      "album_type": "album",
      "images": [
        {
          "url": "https://i.scdn.co/image/ab67616d0000b27388f1c183b6785d39be3ca6d7",
          "height": 640,
          "width": 640
        },
        {
          "url": "https://i.scdn.co/image/ab67616d00001e0288f1c183b6785d39be3ca6d7",
          "height": 300,
          "width": 300
        },
        {
          "url": "https://i.scdn.co/image/ab67616d0000485188f1c183b6785d39be3ca6d7",
          "height": 64,
          "width": 64
        }
      ],
      "artists": [
        {
          "external_urls": {
            "spotify": "https://open.spotify.com/artist/0pkLgeB9j465x1QB2kRoy4"
          },
          "href": "https://api.spotify.com/v1/artists/0pkLgeB9j465x1QB2kRoy4",
          "id": "0pkLgeB9j465x1QB2kRoy4",
          "name": "HAAi",
          "type": "artist",
          "uri": "spotify:artist:0pkLgeB9j465x1QB2kRoy4"
        }
      ],
      "total_tracks": 34
    }
  ]
}