Skip to main content
Choose from our official SDKs or community-maintained libraries to integrate HITL.sh into your application with minimal setup. All SDKs provide typed interfaces, error handling, and built-in retry logic.

Official SDKs

Python SDK

hitl-python - Full-featured Python SDK with async support
pip install hitl-python

Node.js SDK

hitl-js - JavaScript/TypeScript SDK for Node.js and browsers
npm install hitl-js

Go SDK

hitl-go - Go SDK with full type safety and context support
go get github.com/hitl/go-sdk

PHP SDK

hitl-php - PHP SDK with PSR-4 autoloading and Composer support
composer require hitl/php-sdk

Community Libraries

Ruby

hitl-ruby
gem install hitl

Java

hitl-java
Maven/Gradle available

C#

HITL.NET
Install-Package HITL

Rust

hitl-rs
cargo add hitl

Swift

HITLSwift
Swift Package Manager

Kotlin

hitl-kotlin
JVM/Android support

Python SDK

Installation

pip install hitl-python

Quick Start

from hitl import HITLClient
import asyncio

# Initialize client
client = HITLClient(api_key="your_api_key_here")

# Create a loop
loop = client.loops.create(
    name="Content Moderation Team",
    description="Review user-generated content",
    icon="🔍"
)

print(f"Created loop: {loop.name} ({loop.id})")

# Create a request
request = client.requests.create(
    loop_id=loop.id,
    request_text="Please review this user comment for appropriate content.",
    response_type="single_select",
    response_config={
        "options": ["Approve", "Reject", "Needs Review"]
    },
    priority="high"
)

print(f"Created request: {request.id}")

# Wait for completion (blocking)
completed_request = client.requests.wait_for_completion(
    request.id, 
    timeout=300  # 5 minutes
)

print(f"Request completed with response: {completed_request.response_data}")

Async Support

import asyncio
from hitl import AsyncHITLClient

async def main():
    client = AsyncHITLClient(api_key="your_api_key_here")
    
    # Create multiple requests concurrently
    tasks = []
    for i in range(5):
        task = client.requests.create(
            loop_id="your_loop_id",
            request_text=f"Review request #{i+1}",
            response_type="text"
        )
        tasks.append(task)
    
    # Wait for all requests to be created
    requests = await asyncio.gather(*tasks)
    print(f"Created {len(requests)} requests")
    
    # Monitor all requests
    completion_tasks = [
        client.requests.wait_for_completion(req.id, timeout=600)
        for req in requests
    ]
    
    completed = await asyncio.gather(*completion_tasks)
    for req in completed:
        print(f"Request {req.id}: {req.response_data}")

asyncio.run(main())

Advanced Features

from hitl import HITLClient, HITLError, RateLimitError, AuthenticationError

client = HITLClient(
    api_key="your_api_key_here",
    retry_attempts=3,
    retry_delay=1.0
)

try:
    request = client.requests.create(
        loop_id="invalid_loop_id",
        request_text="Test request"
    )
except AuthenticationError:
    print("Invalid API key")
except RateLimitError as e:
    print(f"Rate limited. Retry after: {e.retry_after} seconds")
except HITLError as e:
    print(f"HITL API error: {e.message}")

Node.js SDK

Installation

npm install hitl-js

Quick Start

import { HITLClient } from 'hitl-js';

// Initialize client
const client = new HITLClient({
  apiKey: 'your_api_key_here',
  baseURL: 'https://api.hitl.sh/v1'
});

async function main() {
  try {
    // Create a loop
    const loop = await client.loops.create({
      name: 'Content Moderation Team',
      description: 'Review user-generated content',
      icon: '🔍'
    });
    
    console.log(`Created loop: ${loop.name} (${loop.id})`);
    
    // Create a request
    const request = await client.requests.create({
      loopId: loop.id,
      requestText: 'Please review this user comment for appropriate content.',
      responseType: 'single_select',
      responseConfig: {
        options: ['Approve', 'Reject', 'Needs Review']
      },
      priority: 'high'
    });
    
    console.log(`Created request: ${request.id}`);
    
    // Wait for completion
    const completedRequest = await client.requests.waitForCompletion(
      request.id,
      { timeout: 300000 } // 5 minutes
    );
    
    console.log(`Request completed: ${completedRequest.responseData}`);
    
  } catch (error) {
    if (error instanceof client.RateLimitError) {
      console.log(`Rate limited. Retry after: ${error.retryAfter}ms`);
    } else if (error instanceof client.HITLError) {
      console.log(`HITL API error: ${error.message}`);
    } else {
      console.error('Unexpected error:', error);
    }
  }
}

main();

TypeScript Support

import { HITLClient, Loop, Request, RequestStatus } from 'hitl-js';

interface ContentModerationRequest {
  content: string;
  userId: string;
  reportType: 'spam' | 'harassment' | 'inappropriate';
}

class ContentModerationService {
  private client: HITLClient;
  private moderationLoopId: string;

  constructor(apiKey: string, moderationLoopId: string) {
    this.client = new HITLClient({ apiKey });
    this.moderationLoopId = moderationLoopId;
  }

  async moderateContent(content: ContentModerationRequest): Promise<string> {
    const request = await this.client.requests.create({
      loopId: this.moderationLoopId,
      requestText: `Review ${content.reportType} report:\n\nContent: ${content.content}\nUser: ${content.userId}`,
      responseType: 'single_select',
      responseConfig: {
        options: ['Approve', 'Remove', 'Warn User', 'Suspend User']
      },
      priority: content.reportType === 'harassment' ? 'critical' : 'high',
      metadata: {
        userId: content.userId,
        reportType: content.reportType
      }
    });

    // Use webhook or polling to get the result
    const result = await this.client.requests.waitForCompletion(request.id, {
      timeout: 600000, // 10 minutes
      pollInterval: 5000 // Check every 5 seconds
    });

    return result.responseData as string;
  }

  async getRequestStats(): Promise<{
    total: number;
    pending: number;
    completed: number;
    averageResponseTime: number;
  }> {
    const requests = await this.client.requests.list({
      loopId: this.moderationLoopId,
      limit: 100
    });

    const total = requests.length;
    const pending = requests.filter(r => r.status === 'pending').length;
    const completed = requests.filter(r => r.status === 'completed').length;
    
    const completedRequests = requests.filter(r => r.responseTimeSeconds);
    const averageResponseTime = completedRequests.length > 0
      ? completedRequests.reduce((sum, r) => sum + r.responseTimeSeconds!, 0) / completedRequests.length
      : 0;

    return { total, pending, completed, averageResponseTime };
  }
}

// Usage
const moderationService = new ContentModerationService(
  'your_api_key_here',
  'your_moderation_loop_id'
);

// Moderate content
const decision = await moderationService.moderateContent({
  content: 'Potentially inappropriate user comment...',
  userId: 'user_12345',
  reportType: 'inappropriate'
});

console.log(`Moderation decision: ${decision}`);

Express.js Integration

import express from 'express';
import { HITLClient, WebhookHandler } from 'hitl-js';

const app = express();
const client = new HITLClient({ apiKey: process.env.HITL_API_KEY });
const webhookHandler = new WebhookHandler({ secret: process.env.WEBHOOK_SECRET });

app.use(express.json());

// Webhook endpoint
app.post('/webhook/hitl', async (req, res) => {
  try {
    const event = webhookHandler.parseEvent(req.body, req.headers);
    
    switch (event.type) {
      case 'request.completed':
        await handleRequestCompleted(event.data);
        break;
      case 'request.claimed':
        await handleRequestClaimed(event.data);
        break;
      default:
        console.log(`Unhandled event: ${event.type}`);
    }
    
    res.json({ status: 'success' });
  } catch (error) {
    console.error('Webhook error:', error);
    res.status(400).json({ error: error.message });
  }
});

// API endpoint to create moderation requests
app.post('/api/moderate', async (req, res) => {
  try {
    const { content, type } = req.body;
    
    const request = await client.requests.create({
      loopId: process.env.MODERATION_LOOP_ID,
      requestText: `Review ${type}: ${content}`,
      responseType: 'single_select',
      responseConfig: {
        options: ['Approve', 'Reject', 'Flag for Review']
      },
      priority: 'high'
    });
    
    res.json({ 
      requestId: request.id,
      status: 'submitted',
      estimatedTime: '2-5 minutes'
    });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

async function handleRequestCompleted(data) {
  const { request } = data;
  console.log(`Request ${request.id} completed with: ${request.responseData}`);
  
  // Update your database, send notifications, etc.
}

async function handleRequestClaimed(data) {
  const { request, reviewer } = data;
  console.log(`Request ${request.id} claimed by ${reviewer.email}`);
}

app.listen(3000, () => {
  console.log('Server running on port 3000');
});

Go SDK

Installation

go get github.com/hitl/go-sdk

Quick Start

package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/hitl/go-sdk"
)

func main() {
    // Initialize client
    client := hitl.NewClient("your_api_key_here")
    
    ctx := context.Background()
    
    // Create a loop
    loop, err := client.Loops.Create(ctx, &hitl.CreateLoopRequest{
        Name:        "Content Moderation Team",
        Description: "Review user-generated content",
        Icon:        "🔍",
    })
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("Created loop: %s (%s)\n", loop.Name, loop.ID)
    
    // Create a request
    request, err := client.Requests.Create(ctx, &hitl.CreateRequestRequest{
        LoopID:      loop.ID,
        RequestText: "Please review this user comment for appropriate content.",
        ResponseType: hitl.ResponseTypeSingleSelect,
        ResponseConfig: &hitl.SingleSelectConfig{
            Options: []string{"Approve", "Reject", "Needs Review"},
        },
        Priority: hitl.PriorityHigh,
    })
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("Created request: %s\n", request.ID)
    
    // Wait for completion with timeout
    ctx, cancel := context.WithTimeout(ctx, 5*time.Minute)
    defer cancel()
    
    completedRequest, err := client.Requests.WaitForCompletion(ctx, request.ID)
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("Request completed with response: %v\n", completedRequest.ResponseData)
}

Advanced Usage

package main

import (
    "context"
    "fmt"
    "log"
    "sync"
    "time"

    "github.com/hitl/go-sdk"
)

type ContentModerationService struct {
    client           *hitl.Client
    moderationLoopID string
}

func NewContentModerationService(apiKey, loopID string) *ContentModerationService {
    return &ContentModerationService{
        client:           hitl.NewClient(apiKey),
        moderationLoopID: loopID,
    }
}

func (cms *ContentModerationService) ModerateContent(ctx context.Context, content string, userID string) (string, error) {
    request, err := cms.client.Requests.Create(ctx, &hitl.CreateRequestRequest{
        LoopID:      cms.moderationLoopID,
        RequestText: fmt.Sprintf("Review content from user %s:\n\n%s", userID, content),
        ResponseType: hitl.ResponseTypeSingleSelect,
        ResponseConfig: &hitl.SingleSelectConfig{
            Options: []string{"Approve", "Remove", "Warn User", "Suspend User"},
        },
        Priority: hitl.PriorityHigh,
        Metadata: map[string]interface{}{
            "userID": userID,
            "contentType": "comment",
        },
    })
    if err != nil {
        return "", err
    }

    // Wait for completion with timeout
    completedRequest, err := cms.client.Requests.WaitForCompletion(ctx, request.ID)
    if err != nil {
        return "", err
    }

    return completedRequest.ResponseData.(string), nil
}

func (cms *ContentModerationService) ModerateBatch(ctx context.Context, contents []string) ([]string, error) {
    var wg sync.WaitGroup
    results := make([]string, len(contents))
    errors := make([]error, len(contents))

    // Process up to 10 items concurrently
    semaphore := make(chan struct{}, 10)

    for i, content := range contents {
        wg.Add(1)
        go func(index int, content string) {
            defer wg.Done()
            
            semaphore <- struct{}{} // Acquire
            defer func() { <-semaphore }() // Release
            
            result, err := cms.ModerateContent(ctx, content, fmt.Sprintf("user_%d", index))
            if err != nil {
                errors[index] = err
            } else {
                results[index] = result
            }
        }(i, content)
    }

    wg.Wait()

    // Check for any errors
    for _, err := range errors {
        if err != nil {
            return nil, err
        }
    }

    return results, nil
}

func main() {
    service := NewContentModerationService("your_api_key_here", "your_loop_id")
    
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
    defer cancel()

    // Single content moderation
    result, err := service.ModerateContent(ctx, "This is a test comment", "user123")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Moderation result: %s\n", result)

    // Batch moderation
    contents := []string{
        "First comment to review",
        "Second comment to review", 
        "Third comment to review",
    }
    
    results, err := service.ModerateBatch(ctx, contents)
    if err != nil {
        log.Fatal(err)
    }
    
    for i, result := range results {
        fmt.Printf("Content %d: %s\n", i+1, result)
    }
}

PHP SDK

Installation

composer require hitl/php-sdk

Quick Start

<?php
require_once 'vendor/autoload.php';

use HITL\Client;
use HITL\Exception\HITLException;
use HITL\Exception\RateLimitException;

// Initialize client
$client = new Client([
    'api_key' => 'your_api_key_here',
    'base_url' => 'https://api.hitl.sh/v1'
]);

try {
    // Create a loop
    $loop = $client->loops()->create([
        'name' => 'Content Moderation Team',
        'description' => 'Review user-generated content',
        'icon' => '🔍'
    ]);
    
    echo "Created loop: {$loop['name']} ({$loop['id']})\n";
    
    // Create a request
    $request = $client->requests()->create([
        'loop_id' => $loop['id'],
        'request_text' => 'Please review this user comment for appropriate content.',
        'response_type' => 'single_select',
        'response_config' => [
            'options' => ['Approve', 'Reject', 'Needs Review']
        ],
        'priority' => 'high'
    ]);
    
    echo "Created request: {$request['id']}\n";
    
    // Wait for completion (with polling)
    $completedRequest = $client->requests()->waitForCompletion($request['id'], [
        'timeout' => 300, // 5 minutes
        'poll_interval' => 5 // Check every 5 seconds
    ]);
    
    echo "Request completed with response: {$completedRequest['response_data']}\n";
    
} catch (RateLimitException $e) {
    echo "Rate limited. Retry after: {$e->getRetryAfter()} seconds\n";
} catch (HITLException $e) {
    echo "HITL API error: {$e->getMessage()}\n";
} catch (Exception $e) {
    echo "Unexpected error: {$e->getMessage()}\n";
}
?>

Laravel Integration

<?php
// config/hitl.php
return [
    'api_key' => env('HITL_API_KEY'),
    'base_url' => env('HITL_BASE_URL', 'https://api.hitl.sh/v1'),
    'moderation_loop_id' => env('HITL_MODERATION_LOOP_ID'),
];

// app/Services/ContentModerationService.php
<?php

namespace App\Services;

use HITL\Client;
use Illuminate\Support\Facades\Log;

class ContentModerationService
{
    private Client $client;
    private string $moderationLoopId;

    public function __construct()
    {
        $this->client = new Client([
            'api_key' => config('hitl.api_key'),
            'base_url' => config('hitl.base_url')
        ]);
        $this->moderationLoopId = config('hitl.moderation_loop_id');
    }

    public function moderateContent(string $content, string $userId): string
    {
        $request = $this->client->requests()->create([
            'loop_id' => $this->moderationLoopId,
            'request_text' => "Review content from user {$userId}:\n\n{$content}",
            'response_type' => 'single_select',
            'response_config' => [
                'options' => ['Approve', 'Remove', 'Warn User', 'Suspend User']
            ],
            'priority' => 'high',
            'metadata' => [
                'user_id' => $userId,
                'content_type' => 'comment'
            ]
        ]);

        Log::info("Created moderation request: {$request['id']}");

        // Return request ID for async processing
        return $request['id'];
    }

    public function handleWebhook(array $payload): void
    {
        if ($payload['event'] === 'request.completed') {
            $request = $payload['data']['request'];
            $decision = $request['response_data'];
            
            Log::info("Moderation completed for request {$request['id']}: {$decision}");
            
            // Process the moderation decision
            $this->processDecision($request, $decision);
        }
    }

    private function processDecision(array $request, string $decision): void
    {
        $metadata = $request['metadata'];
        $userId = $metadata['user_id'];
        
        switch ($decision) {
            case 'Remove':
                // Delete the content
                Log::info("Removing content for user {$userId}");
                break;
            case 'Warn User':
                // Send warning to user
                Log::info("Sending warning to user {$userId}");
                break;
            case 'Suspend User':
                // Suspend the user account
                Log::info("Suspending user {$userId}");
                break;
            default:
                // Content approved, no action needed
                Log::info("Content approved for user {$userId}");
        }
    }
}

// app/Http/Controllers/WebhookController.php
<?php

namespace App\Http\Controllers;

use App\Services\ContentModerationService;
use HITL\WebhookHandler;
use Illuminate\Http\Request;
use Illuminate\Http\Response;

class WebhookController extends Controller
{
    private ContentModerationService $moderationService;
    private WebhookHandler $webhookHandler;

    public function __construct(ContentModerationService $moderationService)
    {
        $this->moderationService = $moderationService;
        $this->webhookHandler = new WebhookHandler([
            'secret' => config('hitl.webhook_secret')
        ]);
    }

    public function handle(Request $request): Response
    {
        try {
            $payload = $this->webhookHandler->parseEvent(
                $request->getContent(),
                $request->headers->all()
            );
            
            $this->moderationService->handleWebhook($payload);
            
            return response()->json(['status' => 'success']);
        } catch (\Exception $e) {
            return response()->json(['error' => $e->getMessage()], 400);
        }
    }
}

SDK Comparison

FeaturePythonNode.jsGoPHP
Async Support✅ Full✅ Native✅ Context❌ Sync only
Type Safety✅ Typed✅ TypeScript✅ Strong⚠️ Partial
Webhooks✅ Built-in✅ Built-in✅ Built-in✅ Built-in
Retry Logic✅ Configurable✅ Configurable✅ Configurable✅ Basic
Rate Limiting✅ Auto-handle✅ Auto-handle✅ Auto-handle✅ Auto-handle
Batch Ops✅ Available✅ Available✅ Manual✅ Manual

Next Steps