StateSet API Reference

Welcome to the StateSet API. Our comprehensive REST and GraphQL APIs enable you to build powerful autonomous business applications that scale with your needs.
API Version: v1 (Current) SDK Versions: Node.js v3.2.0 | Python v2.1.0 | Go v1.4.0 | Ruby v2.0.0 Last Updated: January 2025
Production Environment:
  • Base URL: https://api.stateset.com/v1
  • GraphQL: https://api.stateset.com/graphql
  • WebSocket: wss://api.stateset.com/v1/ws
Sandbox Environment:
  • Base URL: https://api.sandbox.stateset.com/v1
  • GraphQL: https://api.sandbox.stateset.com/graphql
  • WebSocket: wss://api.sandbox.stateset.com/v1/ws

Quick Start

1

Get Your API Key

  1. Sign up at stateset.com
  2. Navigate to SettingsAPI Keys
  3. Generate a new API key with appropriate scopes
Store your API key securely and never expose it in client-side code.
2

Make Your First Call

Test the connection with a simple API call:
curl https://api.stateset.com/v1/orders \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json"
3

Explore Resources

Browse our comprehensive API reference to discover all available endpoints and capabilities.

Authentication

StateSet API uses API key authentication with support for multiple authentication methods to suit different use cases.

API Key Types

Key TypePrefixEnvironmentUsage
Live Keysk_live_ProductionReal transactions and data
Test Keysk_test_SandboxDevelopment and testing
Restricted Keyrk_live_ProductionLimited scope access
Publishable Keypk_live_Client-sidePublic operations only

API Key Authentication

curl https://api.stateset.com/v1/orders \
  -H "Authorization: Bearer sk_live_51HqJx2eZvKYlo2CXcQhJZPiQdoJO4v_FGtbA8QTy9E4tY"

Environment Variables

We recommend storing your API keys as environment variables:
# .env.development
STATESET_API_KEY=sk_test_51HqJx2eZvKYlo2CX...
STATESET_WEBHOOK_SECRET=whsec_test_...
STATESET_ENVIRONMENT=sandbox

# .env.production  
STATESET_API_KEY=sk_live_51HqJx2eZvKYlo2CX...
STATESET_WEBHOOK_SECRET=whsec_live_...
STATESET_ENVIRONMENT=production
Never commit API keys to version control. Use environment variables or secure key management services.

Rate Limits

Rate Limits by Plan:
  • Starter: 100 requests/minute, 10,000 requests/day
  • Growth: 1,000 requests/minute, 100,000 requests/day
  • Scale: 5,000 requests/minute, 500,000 requests/day
  • Enterprise: Custom limits up to 10,000 requests/minute
Rate limit headers included in responses:
  • X-RateLimit-Limit: Maximum requests allowed in current window
  • X-RateLimit-Remaining: Requests remaining in current window
  • X-RateLimit-Reset: Unix timestamp when limit resets
  • X-RateLimit-Retry-After: Seconds to wait before retrying (when limited)

Handling Rate Limits

When you exceed rate limits, you’ll receive a 429 Too Many Requests response:
{
  "error": {
    "code": "RATE_LIMITED", 
    "message": "Rate limit exceeded. Please retry after 60 seconds.",
    "retry_after": 60,
    "limit": 1000,
    "remaining": 0,
    "reset_at": "2024-01-15T12:00:00Z"
  }
}
Best practices for handling rate limits:
async function apiRequestWithRetry(url, options, maxRetries = 3) {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      const response = await fetch(url, options);
      
      if (response.status === 429) {
        const retryAfter = response.headers.get('X-RateLimit-Retry-After');
        const delay = retryAfter ? parseInt(retryAfter) * 1000 : Math.pow(2, attempt) * 1000;
        
        if (attempt < maxRetries) {
          await new Promise(resolve => setTimeout(resolve, delay));
          continue;
        }
      }
      
      return response;
    } catch (error) {
      if (attempt === maxRetries) throw error;
      await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 1000));
    }
  }
}

Error Handling

StateSet API uses conventional HTTP response codes and returns detailed error information in JSON format with consistent error structures.

HTTP Status Codes

CodeMeaning
200OK - Request succeeded
201Created - Resource created successfully
400Bad Request - Invalid request parameters
401Unauthorized - Invalid or missing API key
403Forbidden - Insufficient permissions
404Not Found - Resource doesn’t exist
409Conflict - Resource already exists or constraint violation
422Unprocessable Entity - Validation errors
429Too Many Requests - Rate limit exceeded
500Internal Server Error - Something went wrong on our end

Error Response Format

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "details": {
      "field": "email",
      "issue": "Invalid email format",
      "expected": "valid email address",
      "received": "invalid-email"
    },
    "request_id": "req_1NXWPnCo6bFb1KQto6C8OWvE",
    "timestamp": "2024-01-15T10:30:00Z",
    "documentation_url": "https://docs.stateset.com/errors/VALIDATION_ERROR"
  }
}

Common Error Codes

Pagination

List endpoints support both offset-based and cursor-based pagination. We recommend cursor-based pagination for better performance and consistency.

Pagination Parameters

ParameterTypeDefaultMaxDescription
limitinteger10100Number of items per page
cursorstringnull-Cursor for next page (recommended)
offsetinteger010000Number of items to skip
pageinteger1-Page number (deprecated)

Offset-Based Pagination

GET /v1/orders?limit=20&offset=40
More efficient for large datasets and handles real-time data changes:
GET /v1/orders?limit=20&cursor=eyJpZCI6Im9yZF8xMjM0NSJ9
Response format:
{
  "data": [...],
  "pagination": {
    "has_more": true,
    "next_cursor": "eyJpZCI6Im9yZF82Nzg5MCJ9",
    "previous_cursor": "eyJpZCI6Im9yZF8wMTIzNCJ9",
    "total_count": 1250,
    "page_count": 63,
    "current_page": 3
  },
  "meta": {
    "request_id": "req_1NXWPnCo6bFb1KQto6C8OWvE",
    "response_time_ms": 142
  }
}

Filtering and Sorting

Most list endpoints support powerful filtering and sorting capabilities using a consistent query syntax.

Filter Operators

OperatorDescriptionExample
_eqEquals?status_eq=shipped
_neNot equals?status_ne=cancelled
_gtGreater than?amount_gt=100
_gteGreater than or equal?amount_gte=100
_ltLess than?amount_lt=500
_lteLess than or equal?amount_lte=500
_inIn array?status_in=pending,processing
_likePattern match?email_like=%@example.com
_betweenRange?created_between=2024-01-01,2024-01-31

Common Filter Patterns

# Exact match
GET /v1/orders?status=shipped

# Multiple values  
GET /v1/orders?status_in=pending,processing,shipped

# Range queries
GET /v1/orders?created_after=2024-01-01T00:00:00Z
GET /v1/orders?total_amount_gte=100.00&total_amount_lte=500.00

# Search
GET /v1/orders?search=john@example.com

# Complex filtering
GET /v1/orders?status=shipped&created_after=2024-01-01&customer_tier=gold

Sorting

# Sort by field (default: ascending)
GET /v1/orders?sort=created_at

# Specify direction
GET /v1/orders?sort=total_amount&order=desc

# Multiple sort fields
GET /v1/orders?sort=status,created_at&order=asc,desc

Official SDKs

Node.js

npm install stateset-node

Python

pip install stateset-python

Ruby

gem install stateset-ruby

Go

go get github.com/stateset/stateset-go

SDK Quick Example

import { StateSetClient } from 'stateset-node';

const client = new StateSetClient({
  apiKey: process.env.STATESET_API_KEY,
  environment: 'production' // or 'sandbox'
});

// Create an order
const order = await client.orders.create({
  customer_email: 'customer@example.com',
  items: [
    { sku: 'WIDGET-001', quantity: 2, price: 29.99 }
  ]
});

console.log(`Order created: ${order.id}`);

GraphQL API

StateSet offers a powerful GraphQL API for flexible data querying and real-time subscriptions.

GraphQL Endpoint

POST https://api.stateset.com/graphql

Basic Query Example

query GetOrdersWithItems {
  orders(limit: 10, where: {status: {_eq: "shipped"}}) {
    id
    order_number
    status
    total_amount
    customer {
      id
      email
      first_name
      last_name
    }
    line_items {
      id
      sku
      quantity
      price
      product {
        name
        category
      }
    }
  }
}

Real-time Subscriptions

subscription OrderUpdates {
  orders(where: {status: {_in: ["processing", "shipped"]}}) {
    id
    status
    updated_at
  }
}

Webhooks

StateSet can send webhook notifications for important events in your account. Webhooks enable real-time integrations and automated workflows.

Webhook Configuration

  1. Configure endpoints in Dashboard → Settings → Webhooks
  2. Select events to subscribe to
  3. Add webhook signing secret to verify authenticity
  4. Test with webhook simulator

Webhook Events

Webhook Payload Structure

{
  "id": "evt_1NXWPnCo6bFb1KQto6C8OWvE",
  "type": "order.created",
  "created": "2024-01-15T10:30:00Z",
  "data": {
    "object": { /* Full object data */ }
  },
  "previous_attributes": { /* For update events */ },
  "metadata": {
    "workspace_id": "ws_123",
    "user_id": "usr_456",
    "api_version": "2024-01-01"
  }
}

Webhook Security & Verification

// Production-ready webhook verification
const crypto = require('crypto');

function verifyWebhook(payload, signature, secret) {
  // Extract timestamp and signatures
  const elements = signature.split(' ');
  const timestamp = elements.find(e => e.startsWith('t=')).slice(2);
  const signatures = elements.filter(e => e.startsWith('v1=')).map(e => e.slice(3));
  
  // Verify timestamp is within 5 minutes
  const currentTime = Math.floor(Date.now() / 1000);
  if (currentTime - parseInt(timestamp) > 300) {
    throw new Error('Webhook timestamp too old');
  }
  
  // Compute expected signature
  const signedPayload = `${timestamp}.${payload}`;
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(signedPayload)
    .digest('hex');
  
  // Verify signature matches
  const valid = signatures.some(sig => 
    crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expectedSignature))
  );
  
  if (!valid) {
    throw new Error('Invalid webhook signature');
  }
  
  return true;
}

// Express.js webhook handler
app.post('/webhooks/stateset', express.raw({type: 'application/json'}), (req, res) => {
  const signature = req.headers['stateset-signature'];
  const secret = process.env.STATESET_WEBHOOK_SECRET;
  
  try {
    verifyWebhook(req.body, signature, secret);
    const event = JSON.parse(req.body);
    
    // Process webhook event
    switch(event.type) {
      case 'order.created':
        handleOrderCreated(event.data.object);
        break;
      case 'return.approved':
        handleReturnApproved(event.data.object);
        break;
      // ... handle other events
    }
    
    res.json({received: true});
  } catch (error) {
    console.error('Webhook error:', error);
    res.status(400).json({error: 'Webhook verification failed'});
  }
});

Testing

Sandbox Environment

The sandbox environment provides a complete testing environment that mirrors production:
# Sandbox endpoints
REST API: https://api.sandbox.stateset.com/v1
GraphQL: https://api.sandbox.stateset.com/graphql
Webhooks: https://webhooks.sandbox.stateset.com

# Test API keys
Authorization: Bearer sk_test_51HqJx2eZvKYlo2CX...

Test Data

Card NumberScenarioResult
4242 4242 4242 4242Successful paymentAlways succeeds
4000 0000 0000 0002Card declinedAlways fails
4000 0000 0000 9995Insufficient fundsFails with insufficient_funds
4000 0000 0000 0127Incorrect CVCFails CVC check

Idempotency

StateSet API supports idempotency for safely retrying requests without side effects:
Idempotency Keys:
  • Valid for 24 hours after first request
  • Must be unique per API key
  • Recommended format: {resource}-{uuid} (e.g., order-550e8400-e29b-41d4-a716)
# Using idempotency for safe retries
curl -X POST https://api.stateset.com/v1/orders \
  -H "Idempotency-Key: order-550e8400-e29b-41d4-a716" \
  -H "Authorization: Bearer sk_test_..." \
  -d @order.json
// Node.js with automatic retry and idempotency
const { v4: uuidv4 } = require('uuid');

async function createOrderSafely(orderData) {
  const idempotencyKey = `order-${uuidv4()}`;
  
  return await stateset.orders.create(orderData, {
    idempotencyKey,
    maxRetries: 3,
    retryDelay: 1000
  });
}

API Limits & Quotas

Request Limits by Plan

PlanRequests/MinRequests/DayBurst LimitConcurrent Connections
Free601,000100/sec10
Starter10010,000200/sec25
Growth1,000100,0001,000/sec100
Scale5,000500,0005,000/sec500
EnterpriseCustomUnlimitedCustomUnlimited

Resource Limits

ResourceLimitNotes
Max request size10 MBIncrease available for Enterprise
Max response size50 MBPaginate for larger datasets
Webhook timeout30 secondsRetry up to 3 times
File upload size100 MBDirect upload to S3 for larger files
Batch operations1,000 itemsUse async jobs for larger batches

Support and Community

Additional Resources


Ready to get started? Check out our 5-minute quickstart guide or explore the API reference sections below.