> ## Documentation Index
> Fetch the complete documentation index at: https://docs.spacepay.solutions/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks

> Real-time payment notifications with secure signature verification

# Webhooks

Set up webhooks to receive real-time payment notifications. SpacePay signs webhooks using HMAC-SHA256 with the format `timestamp + "." + rawBody`.

<Note>
  **Webhook Setup**: Webhooks are set up in your admin dashboard under Settings
  → Developers → Webhooks. Each webhook endpoint gets its own unique secret key
  for signature verification.
</Note>

## Webhook Event Types

SpacePay sends the following webhook events:

* `payment.created`: Payment has been created and is ready for customer payment
* `payment.updated`: Payment status has been updated (confirmed, failed, expired, etc.)
* `withdrawal.created`: Withdrawal has been created and is ready for customer payment
* `withdrawal.updated`: Withdrawal status has been updated (confirmed, failed, expired, etc.)

## Webhook Payload Structure

<Note>
  Webhook payloads contain a minimal snapshot of the resource. If you need full
  details — such as quotes, deposit address, or receipt — call [Get
  Payment](/api-reference/endpoint/external-payments-get) or [Get
  Withdrawal](/api-reference/endpoint/external-withdrawals-get) using the `id`
  from the payload.
</Note>

<Tabs>
  <Tab title="Payment">
    ```json theme={null}
    {
      "type": "payment.created",
      "data": {
        "payment": {
          "id": "4291f98b-d68c-4eb0-883e-6bc790a41c96",
          "type": "payment",
          "merchantId": "4e29f55d-d6a8-42d7-8230-cb8efeded39e",
          "amountInCents": 250,
          "amountDueCents": 250,
          "currency": "USD",
          "status": "pending",
          "orderId": "Order_1234567890",
          "createdAt": "2025-10-10T21:44:06.733Z"
        }
      },
      "timestamp": "2025-10-10T21:44:07.164Z"
    }
    ```
  </Tab>

  <Tab title="Withdrawal">
    ```json theme={null}
    {
      "type": "withdrawal.created",
      "data": {
        "withdrawal": {
          "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
          "merchantId": "4e29f55d-d6a8-42d7-8230-cb8efeded39e",
          "amountInCents": 5000,
          "currency": "USD",
          "status": "pending",
          "orderId": "order_123",
          "createdAt": "2025-10-10T21:44:06.733Z"
        }
      },
      "timestamp": "2025-10-10T21:44:07.164Z"
    }
    ```
  </Tab>
</Tabs>

## Webhook Headers

SpacePay includes these headers with each webhook:

* `X-SpacePay-Id`: Webhook endpoint ID
* `X-SpacePay-Event-Id`: Unique event identifier
* `X-SpacePay-Timestamp`: Timestamp when webhook was sent
* `X-SpacePay-Delivery-Id`: Unique delivery attempt ID
* `X-SpacePay-Signature`: HMAC-SHA256 signature

## Signature Verification

```javascript theme={null}
import crypto from "crypto";

function verifyWebhookSignature(payload, signature, secret, timestamp) {
  // Create the signed payload: timestamp + "." + rawBody
  const signedPayload = Buffer.concat([
    Buffer.from(timestamp),
    Buffer.from("."),
    Buffer.from(payload, "utf8"),
  ]);

  // Generate HMAC-SHA256 signature
  const expectedSignature = crypto
    .createHmac("sha256", Buffer.from(secret, "utf8"))
    .update(signedPayload)
    .digest("hex");

  // Compare signatures using constant-time comparison
  return crypto.timingSafeEqual(
    Buffer.from(signature, "hex"),
    Buffer.from(expectedSignature, "hex"),
  );
}
```

## Webhook Handler Implementation

```javascript theme={null}
app.post("/webhooks/spacepay", (req, res) => {
  const signature = req.headers["x-spacepay-signature"];
  const timestamp = req.headers["x-spacepay-timestamp"];
  const payload = JSON.stringify(req.body);
  const webhookSecret = process.env.SPACEPAY_WEBHOOK_SECRET;

  // Verify signature
  if (!verifyWebhookSignature(payload, signature, webhookSecret, timestamp)) {
    return res.status(400).json({ error: "Invalid signature" });
  }

  // Handle the event
  const event = req.body;
  console.log(`Received event: ${event.type}`);

  switch (event.type) {
    case "payment.created":
      console.log(`Payment created: ${event.data.payment.id}`);
      console.log(`Order ID: ${event.data.payment.orderId}`);
      console.log(
        `Amount: ${event.data.payment.amountInCents} ${event.data.payment.currency}`,
      );
      console.log(
        `Deposit Address: ${event.data.payment.depositAddress.address}`,
      );
      break;
    case "payment.updated":
      console.log(`Payment updated: ${event.data.payment.id}`);
      console.log(`New status: ${event.data.payment.status}`);
      break;
    default:
      console.log(`Unknown event type: ${event.type}`);
  }

  res.json({ received: true });
});
```

## Webhook Setup

<Steps>
  <Step title="Access Webhook Settings">
    Navigate to Settings → Developers → Webhooks in your admin dashboard.
  </Step>

  <Step title="Add Webhook Endpoint">
    Enter your webhook URL (must be HTTPS) to receive payment notifications.
  </Step>

  <Step title="Test Your Endpoint">
    Use the test webhook feature to verify your endpoint is working correctly.
  </Step>

  <Step title="Save Webhook Secret">
    Copy the webhook secret and store it securely in your environment variables.
  </Step>
</Steps>

## Security Best Practices

<CardGroup cols={2}>
  <Card title="Always Verify Signatures" icon="shield">
    Never process webhook events without verifying the signature first.
  </Card>

  <Card title="Use HTTPS" icon="lock">
    Webhook endpoints must use HTTPS to ensure secure data transmission.
  </Card>

  <Card title="Idempotency" icon="repeat">
    Handle duplicate webhook deliveries gracefully using event IDs.
  </Card>

  <Card title="Timeout Handling" icon="clock">
    Respond to webhooks quickly (within 30 seconds) to avoid timeouts.
  </Card>
</CardGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="SDK Integration" icon="code" href="/developer-docs/sdk-integration">
    Use our official SDK for easier integration.
  </Card>

  <Card title="API Integration" icon="terminal" href="/developer-docs/api-integration">
    Integrate directly with SpacePay's REST APIs.
  </Card>

  <Card title="Testing" icon="flask" href="/developer-docs/testing">
    Learn about test environments and scenarios.
  </Card>

  <Card title="Support" icon="question-circle" href="/trust-operations/support">
    Get help with your integration from our support team.
  </Card>
</CardGroup>
