Skip to content

Game Server Integration

Deliver purchases to players directly on your game servers.

Overview

Pixlpay supports automatic delivery to game servers through:

  • Webhook-based delivery - Your server polls for pending deliveries
  • Plugin integration - Official plugins for popular games

Supported Games

  • Minecraft (Java & Bedrock)
  • Rust
  • Hytale (coming soon)
  • And more via webhooks

Webhook-Based Delivery

The recommended approach is to have your game server plugin poll for pending deliveries.

Flow

1. Customer purchases product
2. Pixlpay creates pending delivery
3. Game server plugin polls /api/external/v1/orders?status=pending
4. Plugin delivers items to player
5. Plugin calls /api/external/v1/orders/{id}/fulfill

Example Plugin Logic

javascript
// Poll for pending orders every 30 seconds
setInterval(async () => {
  const orders = await pixlpay.getOrders({
    payment_status: 'paid',
    status: 'processing'
  });

  for (const order of orders.data) {
    const player = await findPlayer(order.metadata.minecraft_uuid);

    if (player && player.isOnline()) {
      for (const item of order.items) {
        await deliverItem(player, item);
      }
      await pixlpay.fulfillOrder(order.id);
    }
  }
}, 30000);

Real-Time Webhooks

For instant delivery, use webhooks combined with your game server:

Webhook Handler

javascript
app.post('/webhooks/pixlpay', async (req, res) => {
  const event = req.body;

  if (event.event_type === 'order.paid') {
    const order = event.data;

    // Queue delivery command
    await redis.lpush('pending_deliveries', JSON.stringify({
      order_id: order.order_id,
      player_uuid: order.metadata.minecraft_uuid,
      items: order.items
    }));
  }

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

Game Server Plugin

javascript
// In your game server plugin
async function checkPendingDeliveries() {
  const delivery = await redis.rpop('pending_deliveries');

  if (delivery) {
    const data = JSON.parse(delivery);
    const player = getPlayer(data.player_uuid);

    if (player) {
      for (const item of data.items) {
        executeCommand(`give ${player.name} ${item.product_name}`);
      }
      await pixlpay.fulfillOrder(data.order_id);
    } else {
      // Player offline, put back in queue
      await redis.lpush('pending_deliveries', delivery);
    }
  }
}

Product Configuration

Configure delivery commands in your product metadata:

json
{
  "name": "VIP Rank",
  "metadata": {
    "delivery_commands": [
      "lp user {player} parent set vip",
      "give {player} diamond 64"
    ],
    "expiry_commands": [
      "lp user {player} parent set default"
    ]
  }
}

Delivery Status

Track delivery status through order status:

StatusMeaning
processingPayment received, awaiting delivery
completedSuccessfully delivered to player
cancelledOrder cancelled or refunded

Error Handling

javascript
async function deliverWithRetry(order, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      await deliverToPlayer(order);
      await pixlpay.fulfillOrder(order.id);
      return;
    } catch (error) {
      if (attempt === maxRetries) {
        // Log failure, notify admin
        await notifyAdmin(`Delivery failed: ${order.order_number}`);
      }
      await sleep(5000 * attempt);
    }
  }
}

Best Practices

  1. Never store RCON passwords - Use pull-based delivery instead
  2. Queue deliveries - Handle offline players gracefully
  3. Idempotent commands - Ensure commands can be run multiple times safely
  4. Verify player identity - Confirm player UUID matches before delivery
  5. Log everything - Keep records of all deliveries for support

Built for game developers, by game developers.