Skip to content

WebSocket API Reference

PrimeStamp provides a WebSocket API for real-time stamp events, verification updates, and batch progress tracking.

Setup

pip install websockets fastapi
from primestamp.api.websocket import create_websocket_app

app = create_websocket_app()
# WebSocket endpoint: ws://localhost:8800/ws
# Stats endpoint:     GET /ws/stats

Connection

Connect to ws://localhost:8800/ws (or wss:// in production).

All messages are JSON objects with this envelope:

{
  "type": "<message_type>",
  "data": { ... },
  "id": "optional-request-id",
  "timestamp": "2026-04-10T12:00:00+00:00"
}

Message Types

Client-to-Server

Type Description
subscribe Subscribe to a channel
unsubscribe Unsubscribe from a channel
ping Heartbeat ping
stamp Create a stamp via WebSocket
verify Verify a stamp via WebSocket

Server-to-Client

Type Description
subscribed Subscription confirmed
unsubscribed Unsubscription confirmed
pong Heartbeat response
stamp_created A new stamp was created
stamp_confirmed A stamp was confirmed with proof
stamp_anchored A stamp was anchored on-chain
verification_result Verification completed
error Error message
batch_progress Batch operation progress
vault_created A new vault was created
vault_heartbeat A vault heartbeat was received
vault_released A vault was manually released
vault_burned A vault was burned (destroyed)
vault_deadline_warning A vault deadline is approaching

Channels

Subscribe to channels to receive filtered events.

Channel Description
all_stamps All stamp events across the system
user_stamps Stamps belonging to a specific user
stamp Events for a specific stamp (use filters)
batch Progress updates for a specific batch
all_vaults All vault events across the system
user_vaults Vault events for the authenticated user
vault Events for a specific vault (use filters)

Subscription Management

Subscribe

{
  "type": "subscribe",
  "data": {
    "channel": "all_stamps"
  }
}

Subscribe to a specific stamp with filters:

{
  "type": "subscribe",
  "data": {
    "channel": "stamp",
    "filters": { "stamp_id": "ps-abc123" }
  }
}

Response:

{
  "type": "subscribed",
  "data": {
    "channel": "all_stamps",
    "filters": {}
  },
  "id": "original-request-id",
  "timestamp": "2026-04-10T12:00:00+00:00"
}

Unsubscribe

{
  "type": "unsubscribe",
  "data": { "channel": "all_stamps" }
}

Heartbeat

Send periodic pings to keep the connection alive.

Request:

{
  "type": "ping"
}

Response:

{
  "type": "pong",
  "data": { "timestamp": "2026-04-10T12:00:00+00:00" }
}

Creating Stamps

Create a stamp directly over the WebSocket connection.

Request:

{
  "type": "stamp",
  "id": "request-1",
  "data": {
    "contentHash": "sha3-256:e3b0c44298fc1c14...",
    "metadata": { "filename": "report.pdf" }
  }
}

Response (sent to requester):

{
  "type": "stamp_created",
  "id": "request-1",
  "data": {
    "id": "ps-ws-abc123...",
    "contentHash": "sha3-256:e3b0c44298fc1c14...",
    "timestamp": "2026-04-10T12:00:00+00:00",
    "metadata": { "filename": "report.pdf" }
  }
}

The event is also broadcast to all clients subscribed to all_stamps.


Verification

Request:

{
  "type": "verify",
  "id": "verify-1",
  "data": {
    "stampId": "ps-abc123...",
    "contentHash": "sha3-256:e3b0c44298fc1c14..."
  }
}

Response:

{
  "type": "verification_result",
  "id": "verify-1",
  "data": {
    "stampId": "ps-abc123...",
    "contentHash": "sha3-256:e3b0c44298fc1c14...",
    "verified": true,
    "timestamp": "2026-04-10T12:00:00+00:00"
  }
}

Event Notifications

Stamp Confirmed

Received when a stamp receives its cryptographic proof.

{
  "type": "stamp_confirmed",
  "data": {
    "stampId": "ps-abc123...",
    "proof": {
      "primeSignature": "sig-abc123",
      "merkleRoot": "def456..."
    }
  }
}

Stamp Anchored

Received when a stamp is anchored to a blockchain.

{
  "type": "stamp_anchored",
  "data": {
    "stampId": "ps-abc123...",
    "chain": "ethereum",
    "txHash": "0xabc...",
    "timestamp": "2026-04-10T12:05:00+00:00"
  }
}

Batch Progress

Track progress of a batch stamping operation.

{
  "type": "batch_progress",
  "data": {
    "batchId": "batch-xyz",
    "processed": 45,
    "total": 100,
    "percentage": 45.0
  }
}

Vault Events

Subscribe to Vault Events

Subscribe to all vault events or a specific vault:

{
  "type": "subscribe",
  "data": {
    "channel": "all_vaults"
  }
}

Subscribe to a specific vault:

{
  "type": "subscribe",
  "data": {
    "channel": "vault",
    "filters": { "vault_id": "vault-a1b2c3d4..." }
  }
}

Vault Created

Received when a new vault is created.

{
  "type": "vault_created",
  "data": {
    "vaultId": "vault-a1b2c3d4...",
    "state": "active",
    "deadline": "2026-04-13T12:00:00+00:00",
    "contentUris": ["ipfs://Qm...", "arweave://tx123"]
  },
  "timestamp": "2026-04-10T12:00:00+00:00"
}

Vault Heartbeat

Received when a vault heartbeat is submitted.

{
  "type": "vault_heartbeat",
  "data": {
    "vaultId": "vault-a1b2c3d4...",
    "heartbeatAt": "2026-04-11T12:00:00+00:00",
    "nextDeadline": "2026-04-14T12:00:00+00:00",
    "heartbeatCount": 3
  },
  "timestamp": "2026-04-11T12:00:00+00:00"
}

Vault Released

Received when a vault is manually released by its owner.

{
  "type": "vault_released",
  "data": {
    "vaultId": "vault-a1b2c3d4...",
    "releasedAt": "2026-04-11T15:00:00+00:00",
    "reason": "Project handover"
  },
  "timestamp": "2026-04-11T15:00:00+00:00"
}

Vault Burned

Received when a vault is permanently destroyed.

{
  "type": "vault_burned",
  "data": {
    "vaultId": "vault-a1b2c3d4...",
    "burnedAt": "2026-04-12T10:00:00+00:00",
    "reason": "Owner requested destruction"
  },
  "timestamp": "2026-04-12T10:00:00+00:00"
}

Vault Deadline Warning

Received when a vault deadline is approaching (default: 24 hours before expiry).

{
  "type": "vault_deadline_warning",
  "data": {
    "vaultId": "vault-a1b2c3d4...",
    "deadline": "2026-04-13T12:00:00+00:00",
    "hoursRemaining": 24,
    "state": "active"
  },
  "timestamp": "2026-04-12T12:00:00+00:00"
}

JavaScript Client Example

const ws = new WebSocket('wss://api.primestamp.io/ws');

ws.onopen = () => {
    // Subscribe to all stamps
    ws.send(JSON.stringify({
        type: 'subscribe',
        data: { channel: 'all_stamps' }
    }));

    // Subscribe to a specific stamp's lifecycle
    ws.send(JSON.stringify({
        type: 'subscribe',
        data: {
            channel: 'stamp',
            filters: { stamp_id: 'ps-abc123' }
        }
    }));
};

ws.onmessage = (event) => {
    const message = JSON.parse(event.data);

    switch (message.type) {
        case 'stamp_created':
            console.log('New stamp:', message.data);
            break;
        case 'stamp_confirmed':
            console.log('Confirmed:', message.data);
            break;
        case 'stamp_anchored':
            console.log('Anchored:', message.data.chain, message.data.txHash);
            break;
        case 'batch_progress':
            console.log(`Batch: ${message.data.percentage}%`);
            break;
    }
};

// Create a stamp
ws.send(JSON.stringify({
    type: 'stamp',
    id: 'req-1',
    data: {
        contentHash: 'sha3-256:abc123...',
        metadata: { filename: 'doc.pdf' }
    }
}));

Python Client Example

import asyncio
import json
import websockets

async def main():
    async with websockets.connect("ws://localhost:8800/ws") as ws:
        # Subscribe
        await ws.send(json.dumps({
            "type": "subscribe",
            "data": {"channel": "all_stamps"},
        }))

        # Listen for events
        async for message in ws:
            event = json.loads(message)
            print(f"[{event['type']}] {event['data']}")

asyncio.run(main())

Connection Stats

GET /ws/stats
{
  "connectedClients": 42
}

Reconnection

The server does not implement automatic reconnection. Clients should handle WebSocketDisconnect and implement exponential backoff:

function connect() {
    const ws = new WebSocket('wss://api.primestamp.io/ws');
    let retryDelay = 1000;

    ws.onclose = () => {
        setTimeout(() => {
            retryDelay = Math.min(retryDelay * 2, 30000);
            connect();
        }, retryDelay);
    };

    ws.onopen = () => { retryDelay = 1000; };
}