Skip to content
On this page

SDKs & Client Libraries

Production-ready clients for Node.js, Python, Go, and PHP. Shared resilience and worker patterns; the capability matrix below shows where the languages diverge (notably PHP gRPC streaming).

Installation

npm install @spooled/sdk
SDK Package Published
Node.js @spooled/sdk 1.0.40
Python spooled 1.0.24
Go spooled-sdk-go v1.1.0
PHP spooled-cloud/spooled 1.0.21

Install commands above resolve the latest published version. Pin explicitly in production when you need a known-good release.

Capability matrix

One place for parity and gaps. Cells use text and a glyph (not colour alone). Optional install extras are still “Yes” when the feature ships in the package.

Capability Node Python Go PHP
HTTP auto-retries (exp. backoff + jitter) Yes Yes Yes Yes
Circuit breaker Yes Yes Yes Yes
Worker runtime Yes Yes Yes Yes
Realtime WebSocket Python: optional `spooled[realtime]`. PHP: needs `ratchet/pawl`. Yes Yes Yes Yes
Realtime SSE Python: optional `spooled[realtime]`. Yes Yes Yes Yes
gRPC unary client Python: optional `spooled[grpc]`. PHP: needs `ext-grpc`. Yes Yes Yes Yes
gRPC StreamJobs wrapper PHP has generated stubs only — not exposed on SpooledGrpcClient. Yes Yes Yes Not yet
gRPC ProcessJobs wrapper PHP has generated stubs only — not exposed on SpooledGrpcClient. Yes Yes Yes Not yet
Workflow DAGs Yes Yes Yes Yes
Webhook ingestion (GitHub / Stripe / custom) Yes Yes Yes Yes
Dual sync + async clients Python ships SpooledClient and AsyncSpooledClient. Others: one primary concurrency model. Not yet Yes Not yet Not yet

PHP gap: public SpooledGrpcClient exposes unary queue/worker methods only. Generated StreamJobs / ProcessJobs exist on the stub client but are not wrapped — use Node, Python, or Go for streaming gRPC helpers.

Quick start — create a job

Same enqueue call in every language (or cURL):

curl -X POST https://api.spooled.cloud/api/v1/jobs \
  -H "Authorization: Bearer sp_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "queue_name": "my-queue",
    "payload": {
      "event": "user.created",
      "user_id": "usr_123",
      "email": "alice@example.com"
    },
    "idempotency_key": "user-created-usr_123"
  }'

Node.js / TypeScript SDK

Production ready

TypeScript-first client with ESM/CommonJS builds, comprehensive types, worker runtime, and full gRPC streaming helpers (streamJobs / processJobs).

Node.js — Core resources

Jobs

Create, list, claim, complete, fail, retry, cancel

Workers

Register, heartbeat, deregister, SpooledWorker class

Queues

List, get, stats, pause, resume, delete, configure

Schedules

Cron schedules with timezone support

Workflows

DAG execution with job dependencies

DLQ

Dead letter queue operations

Node.js — gRPC client

High-performance gRPC client. Hosted API quotas are enforced server-side and surfaced as typed/structured errors:

import { SpooledGrpcClient } from '@spooled/sdk';

const grpcClient = new SpooledGrpcClient({
  address: 'grpc.spooled.cloud:443',
  apiKey: process.env.SPOOLED_API_KEY!,
  useTls: true,
});

await grpcClient.waitForReady();

// Register worker
const { workerId } = await grpcClient.workers.register({
  queueName: 'emails',
  hostname: 'worker-1',
  maxConcurrency: 10,
});

// Dequeue jobs in batch
const { jobs } = await grpcClient.queue.dequeue({
  queueName: 'emails',
  workerId,
  batchSize: 10,
});

// Process and complete (echo leaseId for lease fencing)
for (const job of jobs) {
  await processJob(job);
  await grpcClient.queue.complete({
    jobId: job.id,
    workerId,
    leaseId: job.leaseId ?? undefined,
    result: { success: true },
  });
}

grpcClient.close();

Performance: gRPC is typically lower-latency than HTTP for high-throughput workers

Node.js — Documentation


Python SDK

Production ready

Sync and async clients, Pydantic models, decorator-based worker runtime, and optional gRPC / realtime extras (pip install spooled[all]).

Python — Quick start

Create a job (from the SDK README / examples/basic_usage.py):

from spooled import SpooledClient

client = SpooledClient(api_key="sp_live_...")

# Create a job
result = client.jobs.create({
    "queue_name": "emails",
    "payload": {
        "to": "user@example.com",
        "subject": "Welcome!",
        "template": "welcome_email",
    },
    "priority": 5,
})

print(f"Job created: {result.id}")

# Get job details
job = client.jobs.get(result.id)
print(f"Status: {job.status}")

client.close()

Process jobs with the worker runtime:

from spooled import SpooledClient
from spooled.worker import SpooledWorker

client = SpooledClient(api_key="sp_live_...")
worker = SpooledWorker(client, queue_name="emails", concurrency=10)

@worker.process
def handle_job(ctx):
    to = ctx.payload["to"]
    subject = ctx.payload["subject"]
    send_email(to, subject)
    return {"sent": True}

worker.start()  # blocking

Optional: pip install spooled[realtime] for WebSocket/SSE, pip install spooled[grpc] for gRPC (includes stream_jobs / process_jobs).

Python — Documentation


Go SDK

Production ready

Idiomatic functional options, context propagation, worker runtime, and public StreamJobs / ProcessJobs wrappers. v1.1.0 is source-breaking for gRPC enqueue: EnqueueRequest.MaxRetries / TimeoutSeconds are *int32 — use grpc.Int32(3), not a bare int.

Go — Quick start

package main

import (
	"context"
	"fmt"
	"os"

	"github.com/spooled-cloud/spooled-sdk-go/spooled"
	"github.com/spooled-cloud/spooled-sdk-go/spooled/resources"
)

func ptr[T any](v T) *T { return &v }

func main() {
	client, err := spooled.NewClient(spooled.WithAPIKey(os.Getenv("SPOOLED_API_KEY")))
	if err != nil {
		panic(err)
	}

	resp, err := client.Jobs().Create(context.Background(), &resources.CreateJobRequest{
		QueueName:      "my-queue",
		Payload:        map[string]any{"key": "value"},
		IdempotencyKey: ptr("unique-key"),
		MaxRetries:     ptr(3),
	})
	if err != nil {
		panic(err)
	}

	fmt.Printf("Created job: %s\n", resp.ID)
}

Go — Documentation


PHP SDK

Production ready

PHP 8.2+ with readonly DTOs, PSR-compatible HTTP/logger, worker runtime, webhook ingestion, and optional unary gRPC. No public StreamJobs / ProcessJobs wrappers yet (see matrix).

PHP — Quick start

<?php

use Spooled\SpooledClient;
use Spooled\Config\ClientOptions;

$client = new SpooledClient(new ClientOptions(
    apiKey: getenv('SPOOLED_API_KEY'),
));

$userId = 'usr_123';

// Create a job
$job = $client->jobs->create([
    'queue' => 'email-notifications',
    'payload' => [
        'to' => 'user@example.com',
        'subject' => 'Welcome!',
        'template' => 'welcome',
    ],
    'idempotencyKey' => "welcome-{$userId}",
    'maxRetries' => 5,
]);

echo "Created job: {$job->id}\n";

PHP — Documentation


Plan limits

The hosted API enforces tier-based quotas (SDKs surface the same 429 / quota errors). Numbers match Limits and backend plans.rs:

Tier Active Jobs Daily Jobs Queues Workers
Free 10 1,000 2 1
Starter 500 10,000 10 5
Pro 5,000 100,000 50 25
Enterprise Unlimited Unlimited Unlimited Unlimited

See the Limits documentation for the full matrix (API keys, schedules, workflows, payload size, rate limits, retention).

Dashboard tip

Account → Usage

What to look for:

  • Current usage vs plan limits
  • Jobs created today
  • Active workers and queues

Actions:

  • Upgrade plan if approaching limits
  • Monitor usage trends

Need help?

Last updated 2026-09-10