[TERMINAL · SKILLS]
> mounting /skills...
> indexing 295 manifests...
> linking agents: claude · codex · gemini · cursor
> ready.
[░░░░░░░░░░░░░░░░░░░░░░░░░░░░] 0%
Terminal.skills
Use Cases/Build an API Sandbox Environment

Build an API Sandbox Environment

Build an API sandbox environment with isolated test data, mock payment processing, realistic responses, rate limit simulation, and developer onboarding for safe API integration testing.

#redis#caching#database#pub-sub#queues
Works with:claude-codeopenai-codexgemini-clicursor

Skills stack · 5 skills

Avg quality 93/100·All SAFE
>

typescript

v

Not yet scored
View skill
>

redis

v1.0.0

Build applications with Redis — caching, session storage, pub/sub, streams, rate limiting, leaderboards, and queues. Use when tasks involve in-memory data storage, real-time messaging, distributed locking, or performance optimization with caching layers.

93/100 quality
1.81× impact
SAFE
View skill
>

postgresql

v1.0.0

Assists with designing schemas, writing performant queries, managing indexes, and operating PostgreSQL databases. Use when working with JSONB, full-text search, window functions, CTEs, row-level security, replication, or performance tuning. Trigger words: postgresql, postgres, sql, database, jsonb, rls, window functions, cte.

87/100 quality
1.53× impact
SAFE
View skill
>

hono

v1.0.0

You are an expert in Hono, the ultrafast web framework for the edge. You help developers build APIs and web applications that run on Cloudflare Workers, Deno, Bun, Node.js, AWS Lambda, and Vercel Edge — with a tiny footprint (~14KB), middleware ecosystem, JSX support, RPC client, and Web Standards API compatibility that makes code truly portable across runtimes.

93/100 quality
3.00× impact
SAFE
View skill
>

zod

v1.0.0

You are an expert in Zod, the TypeScript-first schema declaration and validation library. You help developers define schemas that validate data at runtime AND infer TypeScript types at compile time — eliminating the need to write types and validators separately. Used for API input validation, form validation, environment variables, config files, and any data boundary.

100/100 quality
1.21× impact
SAFE
View skill
$

The Problem

Lisa leads DX at a 20-person payments API company. Developers integrating their API need to test without processing real payments. Current approach: test API keys that still hit the real database and rate limiter. A customer's load test in "test mode" accidentally created 1M records in the production database. Sandbox responses don't match production format exactly, causing integration bugs. They need a proper sandbox: isolated data, mock payment processing with configurable responses, exact production response format, rate limit simulation, and pre-seeded test data.

Step 1: Build the Sandbox Engine

typescript
import { Redis } from "ioredis";
import { Pool } from "pg";
import { randomBytes } from "node:crypto";
const redis = new Redis(process.env.REDIS_URL!);

// Separate sandbox database
const sandboxPool = new Pool({ connectionString: process.env.SANDBOX_DATABASE_URL });

interface SandboxConfig { apiKeyPrefix: string; dataIsolation: boolean; mockPayments: boolean; simulateLatency: boolean; simulateErrors: boolean; errorRate: number; latencyMs: number; }

const SANDBOX_CONFIG: SandboxConfig = { apiKeyPrefix: "sk_test_", dataIsolation: true, mockPayments: true, simulateLatency: true, simulateErrors: true, errorRate: 0.02, latencyMs: 50 };

// Test card numbers with predefined outcomes
const TEST_CARDS: Record<string, { status: string; declineCode?: string }> = {
  "4242424242424242": { status: "succeeded" },
  "4000000000000002": { status: "failed", declineCode: "card_declined" },
  "4000000000009995": { status: "failed", declineCode: "insufficient_funds" },
  "4000000000000069": { status: "failed", declineCode: "expired_card" },
  "4000000000000127": { status: "failed", declineCode: "incorrect_cvc" },
  "4000000000003220": { status: "requires_action" },
};

// Middleware: route sandbox requests to isolated environment
export function sandboxMiddleware() {
  return async (c: any, next: any) => {
    const apiKey = c.req.header("Authorization")?.replace("Bearer ", "") || c.req.header("X-API-Key") || "";
    const isSandbox = apiKey.startsWith(SANDBOX_CONFIG.apiKeyPrefix);
    c.set("isSandbox", isSandbox);
    c.set("dbPool", isSandbox ? sandboxPool : undefined);

    if (isSandbox) {
      c.header("X-Sandbox", "true");
      // Simulate latency
      if (SANDBOX_CONFIG.simulateLatency) await new Promise((r) => setTimeout(r, SANDBOX_CONFIG.latencyMs + Math.random() * 50));
      // Simulate random errors
      if (SANDBOX_CONFIG.simulateErrors && Math.random() < SANDBOX_CONFIG.errorRate) {
        return c.json({ error: { type: "api_error", message: "Simulated server error (sandbox)" } }, 500);
      }
    }
    await next();
  };
}

// Mock payment processing
export async function processSandboxPayment(params: { amount: number; currency: string; cardNumber: string; customerId: string }): Promise<any> {
  const testCard = TEST_CARDS[params.cardNumber];
  const paymentId = `pi_test_${randomBytes(12).toString("hex")}`;

  if (!testCard) {
    return { id: paymentId, status: "succeeded", amount: params.amount, currency: params.currency, created: Math.floor(Date.now() / 1000), livemode: false };
  }

  if (testCard.status === "failed") {
    return { id: paymentId, status: "failed", amount: params.amount, currency: params.currency, last_payment_error: { code: testCard.declineCode, message: `Your card was declined: ${testCard.declineCode}` }, created: Math.floor(Date.now() / 1000), livemode: false };
  }

  if (testCard.status === "requires_action") {
    return { id: paymentId, status: "requires_action", amount: params.amount, currency: params.currency, client_secret: `${paymentId}_secret_test`, created: Math.floor(Date.now() / 1000), livemode: false };
  }

  return { id: paymentId, status: testCard.status, amount: params.amount, currency: params.currency, created: Math.floor(Date.now() / 1000), livemode: false };
}

// Seed sandbox with test data
export async function seedSandbox(apiKey: string): Promise<{ customers: number; products: number }> {
  const orgId = apiKey.replace(SANDBOX_CONFIG.apiKeyPrefix, "").slice(0, 8);
  // Create test customers
  const customers = ["Test Customer 1", "Test Customer 2", "Test Enterprise Corp", "Sandbox User", "Demo Account"];
  for (const name of customers) {
    await sandboxPool.query(
      `INSERT INTO customers (id, organization_id, name, email, created_at) VALUES ($1, $2, $3, $4, NOW()) ON CONFLICT DO NOTHING`,
      [`cus_test_${randomBytes(6).toString("hex")}`, orgId, name, `${name.toLowerCase().replace(/\s/g, ".")}@test.com`]
    );
  }
  // Create test products
  const products = [{ name: "Basic Plan", price: 999 }, { name: "Pro Plan", price: 2999 }, { name: "Enterprise", price: 9999 }];
  for (const prod of products) {
    await sandboxPool.query(
      `INSERT INTO products (id, organization_id, name, price, currency, created_at) VALUES ($1, $2, $3, $4, 'usd', NOW()) ON CONFLICT DO NOTHING`,
      [`prod_test_${randomBytes(6).toString("hex")}`, orgId, prod.name, prod.price]
    );
  }
  return { customers: customers.length, products: products.length };
}

// Reset sandbox data
export async function resetSandbox(apiKey: string): Promise<void> {
  const orgId = apiKey.replace(SANDBOX_CONFIG.apiKeyPrefix, "").slice(0, 8);
  await sandboxPool.query("DELETE FROM payments WHERE organization_id = $1", [orgId]);
  await sandboxPool.query("DELETE FROM customers WHERE organization_id = $1", [orgId]);
  await sandboxPool.query("DELETE FROM products WHERE organization_id = $1", [orgId]);
  await seedSandbox(apiKey);
}

Results

  • 1M accidental records prevented — sandbox uses separate database; load tests can't affect production; complete data isolation
  • Test cards with predictable outcomes4242... always succeeds; 4000...0002 always declines; developers test every error path without real transactions
  • Exact production format — sandbox responses have identical structure, field names, and types as production; no integration surprises when going live
  • Pre-seeded test data — developer gets sandbox key → 5 test customers + 3 products ready; start building immediately; no manual setup
  • Error simulation — 2% random errors + configurable latency; developers build resilient integrations; discover retry bugs in development, not production