← Back to home
Skubber Logo

API Documentation

Pusher-compatible REST API

📋 View the interactive Swagger UI

📘 Introduction

Skubber Push Server supports the Pusher Channels REST API endpoints, providing a drop-in replacement for Pusher. Use the same API structure but with simpler authentication and without expensive subscriptions.

✨ Benefits:
  • Same API endpoints as Pusher
  • Simpler authentication (no HMAC signatures)
  • Up to 90% cheaper than Pusher
  • Unlimited messages and connections (Premium)
  • Full control over your data

🔐 Authentication

REST API Endpoints

Authentication uses HTTP headers with your API Key and Secret. No complex HMAC SHA256 signatures required!

X-Api-Key: mps_htU8zSQ4LtzyjzIhLV15mPSIk3zSJSaw
X-Api-Secret: qSgM0erFzC3JpB2fsR966MhsbpbTxqfoO1prBSB1VtnbbAnf

Or as query parameters:

?apiKey=your-api-key&apiSecret=your-api-secret

SignalR Connections (Browser/Client)

⚠️ IMPORTANT: NEVER send your API Secret to the browser! Use a JWT token instead:

// Step 1: Get JWT token (server-side or via secure endpoint)
const response = await fetch('https://sps.skubber.com:5187/api/auth/signalr-token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
        apiKey: 'mps_htU8zSQ4LtzyjzIhLV15mPSIk3zSJSaw',
        apiSecret: 'qSgM0erFzC3JpB2fsR966MhsbpbTxqfoO1prBSB1VtnbbAnf'
    })
});
const { token } = await response.json();

// Step 2: Use only the token for SignalR (safe!)
const connection = new signalR.HubConnectionBuilder()
    .withUrl(`https://sps.skubber.com:5187/push?userId=user123&access_token=${token}`)
    .build();
💡 Why JWT tokens?
JWT tokens are temporary (expire after 1 hour) and contain no secrets. If someone steals your token, they have limited-time access and cannot generate new tokens. Your API Secret stays safe on the server!

🚀 Available Endpoints

POST /apps/{appId}/events

Trigger Event

Sends an event to one or more channels.

Parameter / Type / Description

ParameterTypeDescription
name RequiredstringEvent name
data RequiredstringEvent data as JSON string (max 10KB)
channel OptionalstringSingle channel name
channels OptionalarrayArray of channel names (max 100)
socket_id OptionalstringExclude specific connection
info OptionalstringComma-separated list: user_count, subscription_count

Example Request:

{
  "name": "my-event",
  "data": "{\"message\":\"Hello World\"}",
  "channels": ["test-channel", "another-channel"]
}

Response:

{}

Or with info:

{
  "channels": {
    "presence-room": {
      "user_count": 42,
      "subscription_count": 51
    }
  }
}
POST /apps/{appId}/batch_events

Batch Events

Sends multiple events at once (max 10 per batch).

Example Request:

{
  "batch": [
    { "name": "event1", "channel": "channel1", "data": "{\"key\":\"value\"}" },
    { "name": "event2", "channel": "channel2", "data": "{\"other\":\"data\"}" }
  ]
}

Response:

{ "batch": [{}, {}] }
GET /apps/{appId}/channels

Get Channels

Retrieve list of active channels.

ParameterDescription
filter_by_prefixFilter channels by prefix (e.g. "presence-")
infoComma-separated list of attributes
{
  "channels": {
    "presence-room1": { "user_count": 42 },
    "my-channel": { "subscription_count": 10 }
  }
}
GET /apps/{appId}/channels/{channelName}

Get Channel Info

Retrieve info about a specific channel.

{ "occupied": true, "user_count": 42, "subscription_count": 51 }
GET /apps/{appId}/channels/{channelName}/users

Get Channel Users

Retrieve list of users in a presence channel.

Note: Only available for presence channels (name starts with "presence-")
{ "users": [ { "id": "user1" }, { "id": "user2" } ] }
POST /apps/{appId}/users/{userId}/terminate_connections

Terminate User Connections

Terminates all connections for a specific user.

Note: Requires admin scope in API key
{}

🔄 Migration from Pusher

To migrate from Pusher to Skubber:

1. Change the base URL

// From:
https://api-{cluster}.pusher.com

// To:
https://sps.skubber.com:5187

2. Update authentication

// Pusher (complex):
auth: { params: { auth_key: '...', auth_signature: '...', auth_timestamp: '...', body_md5: '...' } }

// Skubber (simple):
headers: { 'X-Api-Key': 'your-api-key', 'X-Api-Secret': 'your-api-secret' }

3. Use the same endpoints

All endpoint paths remain the same!

💻 Code Examples

cURL

curl -X POST "https://sps.skubber.com:5187/apps/myapp/events" \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: your-api-key" \
  -H "X-Api-Secret: your-api-secret" \
  -d '{ "name": "my-event", "channels": ["test-channel"], "data": "{\"message\":\"Hello World\"}" }'

JavaScript / Node.js

const response = await fetch('https://sps.skubber.com:5187/apps/myapp/events', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json', 'X-Api-Key': 'your-api-key', 'X-Api-Secret': 'your-api-secret' },
  body: JSON.stringify({ name: 'my-event', channels: ['test-channel'], data: JSON.stringify({ message: 'Hello World' }) })
});

Python

import requests, json
requests.post('https://sps.skubber.com:5187/apps/myapp/events',
    headers={ 'Content-Type': 'application/json', 'X-Api-Key': 'your-api-key', 'X-Api-Secret': 'your-api-secret' },
    json={ 'name': 'my-event', 'channels': ['test-channel'], 'data': json.dumps({'message': 'Hello World'}) }
)

C#

using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Api-Key", "your-api-key");
client.DefaultRequestHeaders.Add("X-Api-Secret", "your-api-secret");
var response = await client.PostAsJsonAsync("https://sps.skubber.com:5187/apps/myapp/events", new {
    name = "my-event", channels = new[] { "test-channel" },
    data = JsonSerializer.Serialize(new { message = "Hello World" })
});

🎯 Limitations

  • Max 10KB per event (same as Pusher)
  • Max 100 channels per event (same as Pusher)
  • Max 10 events per batch (same as Pusher)
✅ Ready to get started?
Request your API Key and start pushing messages within 5 minutes!