Skip to main content

Documentation Index

Fetch the complete documentation index at: https://playcamp.io/docs/llms.txt

Use this file to discover all available pages before exploring further.

The SDK API sends notifications to your game server when events occur.

Event Types

EventDescription
coupon.redeemedCoupon redeemed
payment.createdPayment registered
payment.bulk_createdBulk payment registered
sponsor.createdBoost registered
sponsor.endedBoost removed

Webhook Format

Headers
Content-Type: application/json
X-Webhook-Batch: true
X-Webhook-Signature: {HMAC-SHA256 signature}
Payload
{
  "events": [
    {
      "event": "payment.created",
      "timestamp": "2024-01-15T10:30:00.000Z",
      "callbackId": "my-callback-001",
      "data": {
        "transactionId": "txn_abc123",
        "userId": "user_12345",
        "amount": 9900,
        "currency": "KRW",
        "creatorKey": "ABC12"
      }
    }
  ]
}

Signature Verification

Verify that webhook requests actually come from PlayCamp.
The SDK provides a verifyWebhook() utility that handles signature verification, timestamp validation, and payload parsing:
import { verifyWebhook } from '@playcamp/node-sdk';

app.post('/webhooks/playcamp', (req, res) => {
  const result = verifyWebhook({
    payload: req.rawBody,
    signature: req.headers['x-webhook-signature'],
    secret: process.env.WEBHOOK_SECRET,
    tolerance: 300,  // Max age in seconds (default: 300)
  });

  if (!result.valid) {
    return res.status(401).json({ error: result.error });
  }

  for (const event of result.payload.events) {
    switch (event.event) {
      case 'coupon.redeemed':
        console.log('Coupon redeemed:', event.data.couponCode);
        break;
      case 'payment.created':
        console.log('Payment created:', event.data.transactionId);
        break;
      case 'payment.bulk_created':
        console.log('Bulk payment:', event.data.totalRequested);
        break;
      case 'sponsor.created':
        console.log('Boost created:', event.data.userId);
        break;
      case 'sponsor.ended':
        console.log('Boost ended:', event.data.userId);
        break;
    }
  }

  res.status(200).json({ received: true });
});

Reception Example (Express)

import { verifyWebhook } from '@playcamp/node-sdk';

app.post('/webhooks/playcamp', express.raw({ type: 'application/json' }), (req, res) => {
  const payload = Buffer.isBuffer(req.body) ? req.body.toString() : req.body;

  const result = verifyWebhook({
    payload,
    signature: req.headers['x-webhook-signature'] as string,
    secret: process.env.WEBHOOK_SECRET!,
  });

  if (!result.valid) {
    return res.status(401).json({ error: result.error });
  }

  for (const event of result.payload.events) {
    console.log('callbackId:', event.callbackId); // webhook tracking ID
    switch (event.event) {
      case 'coupon.redeemed':
        console.log('Coupon redeemed:', event.data);
        break;
      case 'payment.created':
        console.log('Payment created:', event.data);
        break;
      case 'payment.bulk_created':
        console.log('Bulk payment:', event.data);
        break;
      case 'sponsor.created':
        console.log('Boost created:', event.data);
        break;
      case 'sponsor.ended':
        console.log('Boost ended:', event.data);
        break;
    }
  }

  res.json({ received: true });
});
Use express.raw({ type: 'application/json' }) instead of express.json() to enable signature verification with the raw body.

callbackId Tracking

When you pass a callbackId with an API request, webhook events triggered by that request will include the same callbackId. This lets you match requests to their webhook events.
{
  "events": [
    {
      "event": "payment.created",
      "timestamp": "2026-03-17T12:00:00Z",
      "callbackId": "my-callback-001",
      "data": { "transactionId": "txn_abc123", "userId": "user_12345" }
    }
  ]
}

Event Payloads

{
  "events": [
    {
      "event": "sponsor.ended",
      "timestamp": "2024-01-15T10:30:00.000Z",
      "callbackId": "game-session-abc123",
      "data": {
        "userId": "user_12345",
        "campaignId": "campaign_001",
        "creatorKey": "ABC12"
      }
    }
  ]
}

payment.bulk_created

A summary event triggered once per bulk payment request.
{
  "events": [
    {
      "event": "payment.bulk_created",
      "timestamp": "2026-03-17T12:00:00Z",
      "callbackId": "bulk-001",
      "data": {
        "totalRequested": 100,
        "successful": 98,
        "failed": 1,
        "skipped": 1,
        "transactionIds": ["txn_001", "txn_002"]
      }
    }
  ]
}

Testing Webhooks

Generate test signatures for local development:
import { constructWebhookSignature } from '@playcamp/node-sdk';

const payload = JSON.stringify({
  events: [{
    event: 'coupon.redeemed',
    timestamp: new Date().toISOString(),
    data: { couponCode: 'TEST', userId: 'user_123', usageId: 1, reward: [] },
  }]
});

const signature = constructWebhookSignature(payload, 'your_webhook_secret');

Webhook Management

FunctionMethodEndpoint
List webhooksGET/v1/server/webhooks
Create webhookPOST/v1/server/webhooks
Update webhookPUT/v1/server/webhooks/:id
Delete webhookDELETE/v1/server/webhooks/:id
Get webhook logsGET/v1/server/webhooks/:id/logs
Test webhookPOST/v1/server/webhooks/:id/test