> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stateset.com/llms.txt
> Use this file to discover all available pages before exploring further.

# API Reference

> Complete reference for the StateSet API - Build powerful autonomous business applications

# 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.

<Info>
  **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 2026
</Info>

<CardGroup cols={2}>
  <Card title="REST API" icon="link" href="#rest-api">
    RESTful endpoints for all StateSet resources
  </Card>

  <Card title="GraphQL API" icon="diagram-project" href="#graphql-api">
    Flexible queries with real-time subscriptions
  </Card>

  <Card title="SDKs" icon="code" href="#official-sdks">
    Official SDKs for popular languages
  </Card>

  <Card title="Webhooks" icon="webhook" href="#webhooks">
    Real-time event notifications
  </Card>
</CardGroup>

<Note>
  **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`
</Note>

## Quick Start

<Steps>
  <Step title="Get Your API Key">
    1. Sign up at [stateset.com](https://stateset.com)
    2. Navigate to **Settings** → **API Keys**
    3. Generate a new API key with appropriate scopes

    <Warning>
      Store your API key securely and never expose it in client-side code.
    </Warning>
  </Step>

  <Step title="Make Your First Call">
    Test the connection with a simple API call:

    ```bash theme={null}
    curl https://api.stateset.com/v1/orders \
      -H "Authorization: Bearer sk_live_..." \
      -H "Content-Type: application/json"
    ```
  </Step>

  <Step title="Explore Resources">
    Browse our comprehensive API reference to discover all available endpoints and capabilities.
  </Step>
</Steps>

## Authentication

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

### API Key Types

| Key Type            | Prefix     | Environment | Usage                      |
| ------------------- | ---------- | ----------- | -------------------------- |
| **Live Key**        | `sk_live_` | Production  | Real transactions and data |
| **Test Key**        | `sk_test_` | Sandbox     | Development and testing    |
| **Restricted Key**  | `rk_live_` | Production  | Limited scope access       |
| **Publishable Key** | `pk_live_` | Client-side | Public operations only     |

### API Key Authentication

<CodeGroup>
  ```bash cURL theme={null}
  curl https://api.stateset.com/v1/orders \
    -H "Authorization: Bearer ${STATESET_API_KEY}"
  ```

  ```javascript JavaScript/Node.js theme={null}
  // Using fetch
  const response = await fetch('https://api.stateset.com/v1/orders', {
    headers: {
      'Authorization': `Bearer ${process.env.STATESET_API_KEY}`,
      'Content-Type': 'application/json'
    }
  });

  // Using our SDK
  import { StateSetClient } from 'stateset-node';
  const client = new StateSetClient({
    apiKey: process.env.STATESET_API_KEY
  });
  ```

  ```python Python theme={null}
  import requests
  import os

  # Using requests
  response = requests.get(
      'https://api.stateset.com/v1/orders',
      headers={
          'Authorization': f'Bearer {os.getenv("STATESET_API_KEY")}',
          'Content-Type': 'application/json'
      }
  )

  # Using our SDK
  from stateset import StateSet
  client = StateSet(api_key=os.getenv("STATESET_API_KEY"))
  ```

  ```go Go theme={null}
  package main

  import (
      "net/http"
      "os"
  )

  func main() {
      client := &http.Client{}
      req, _ := http.NewRequest("GET", "https://api.stateset.com/v1/orders", nil)
      req.Header.Add("Authorization", "Bearer " + os.Getenv("STATESET_API_KEY"))
      req.Header.Add("Content-Type", "application/json")
      resp, _ := client.Do(req)
  }
  ```
</CodeGroup>

### Environment Variables

We recommend storing your API keys as environment variables:

```bash theme={null}
# .env.development
STATESET_API_KEY=sk_test_your_actual_key_here
STATESET_WEBHOOK_SECRET=whsec_test_...
STATESET_ENVIRONMENT=sandbox

# .env.production  
STATESET_API_KEY=sk_live_your_actual_key_here
STATESET_WEBHOOK_SECRET=whsec_live_...
STATESET_ENVIRONMENT=production
```

<Warning>
  Never commit API keys to version control. Use environment variables or secure key management services.
</Warning>

## Rate Limits

<Info>
  **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)
</Info>

### Handling Rate Limits

When you exceed rate limits, you'll receive a `429 Too Many Requests` response:

```json theme={null}
{
  "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:**

<CodeGroup>
  ```javascript Exponential Backoff theme={null}
  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));
      }
    }
  }
  ```

  ```python Python Retry Logic theme={null}
  import time
  import requests
  from requests.adapters import HTTPAdapter
  from urllib3.util.retry import Retry

  def create_session_with_retries():
      session = requests.Session()
      retry_strategy = Retry(
          total=3,
          status_forcelist=[429, 500, 502, 503, 504],
          backoff_factor=1,
          respect_retry_after_header=True
      )
      adapter = HTTPAdapter(max_retries=retry_strategy)
      session.mount("https://", adapter)
      return session

  # Usage
  session = create_session_with_retries()
  response = session.get('https://api.stateset.com/v1/orders', 
                        headers={'Authorization': 'Bearer your_key'})
  ```
</CodeGroup>

## Error Handling

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

### HTTP Status Codes

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

### Error Response Format

```json theme={null}
{
  "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

<AccordionGroup>
  <Accordion title="Authentication Errors">
    * `INVALID_API_KEY`: API key is invalid or expired
    * `MISSING_API_KEY`: No API key provided
    * `INSUFFICIENT_PERMISSIONS`: API key doesn't have required permissions
  </Accordion>

  <Accordion title="Validation Errors">
    * `VALIDATION_ERROR`: Request data failed validation
    * `MISSING_REQUIRED_FIELD`: Required field not provided
    * `INVALID_FIELD_FORMAT`: Field format is incorrect
  </Accordion>

  <Accordion title="Resource Errors">
    * `RESOURCE_NOT_FOUND`: Requested resource doesn't exist
    * `RESOURCE_ALREADY_EXISTS`: Resource with same identifier exists
    * `RESOURCE_CONFLICT`: Operation conflicts with current resource state
  </Accordion>
</AccordionGroup>

## Pagination

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

### Pagination Parameters

| Parameter | Type    | Default | Max   | Description                        |
| --------- | ------- | ------- | ----- | ---------------------------------- |
| `limit`   | integer | 10      | 100   | Number of items per page           |
| `cursor`  | string  | null    | -     | Cursor for next page (recommended) |
| `offset`  | integer | 0       | 10000 | Number of items to skip            |
| `page`    | integer | 1       | -     | Page number (deprecated)           |

### Offset-Based Pagination

```bash theme={null}
GET /v1/orders?limit=20&offset=40
```

### Cursor-Based Pagination (Recommended)

More efficient for large datasets and handles real-time data changes:

```bash theme={null}
GET /v1/orders?limit=20&cursor=eyJpZCI6Im9yZF8xMjM0NSJ9
```

**Response format:**

```json theme={null}
{
  "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

| Operator   | Description           | Example                                  |
| ---------- | --------------------- | ---------------------------------------- |
| `_eq`      | Equals                | `?status_eq=shipped`                     |
| `_ne`      | Not equals            | `?status_ne=cancelled`                   |
| `_gt`      | Greater than          | `?amount_gt=100`                         |
| `_gte`     | Greater than or equal | `?amount_gte=100`                        |
| `_lt`      | Less than             | `?amount_lt=500`                         |
| `_lte`     | Less than or equal    | `?amount_lte=500`                        |
| `_in`      | In array              | `?status_in=pending,processing`          |
| `_like`    | Pattern match         | `?email_like=%@example.com`              |
| `_between` | Range                 | `?created_between=2024-01-01,2024-01-31` |

### Common Filter Patterns

```bash theme={null}
# 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

```bash theme={null}
# 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

<CardGroup cols={2}>
  <Card title="Node.js" icon="node-js">
    ```bash theme={null}
    npm install stateset-node
    ```
  </Card>

  <Card title="Python" icon="python">
    ```bash theme={null}
    pip install stateset-python
    ```
  </Card>

  <Card title="Ruby" icon="gem">
    ```bash theme={null}
    gem install stateset-ruby
    ```
  </Card>

  <Card title="Go" icon="golang">
    ```bash theme={null}
    go get github.com/stateset/stateset-go
    ```
  </Card>
</CardGroup>

### SDK Quick Example

<CodeGroup>
  ```javascript Node.js theme={null}
  import { StateSetClient } from 'stateset-node';

  // Replace with a structured logger (Winston, Pino, etc) in production
  const logger = console;

  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 }
    ]
  });

  logger.info('Order created', { orderId: order.id });
  ```

  ```python Python theme={null}
  from stateset import StateSet

  client = StateSet(
      api_key=os.getenv('STATESET_API_KEY'),
      environment='production'
  )

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

  print(f'Order created: {order.id}')
  ```
</CodeGroup>

## 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

```graphql theme={null}
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

```graphql theme={null}
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

<AccordionGroup>
  <Accordion title="Order Events">
    * `order.created` - New order placed
    * `order.updated` - Order details modified
    * `order.paid` - Payment confirmed
    * `order.processing` - Order processing started
    * `order.shipped` - Shipment created
    * `order.delivered` - Delivery confirmed
    * `order.cancelled` - Order cancelled
    * `order.refunded` - Refund processed
  </Accordion>

  <Accordion title="Return Events">
    * `return.created` - Return initiated
    * `return.approved` - Return approved
    * `return.received` - Items received
    * `return.processed` - Return completed
    * `return.rejected` - Return rejected
  </Accordion>

  <Accordion title="Inventory Events">
    * `inventory.low_stock` - Stock below threshold
    * `inventory.out_of_stock` - Item out of stock
    * `inventory.updated` - Stock levels changed
    * `inventory.transfer` - Stock transferred
  </Accordion>

  <Accordion title="Customer Events">
    * `customer.created` - New customer registered
    * `customer.updated` - Customer profile updated
    * `customer.deleted` - Customer deleted
    * `customer.subscription.created` - Subscription started
    * `customer.subscription.cancelled` - Subscription cancelled
  </Accordion>
</AccordionGroup>

### Webhook Payload Structure

```json theme={null}
{
  "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

```javascript theme={null}
// Production-ready webhook verification
const crypto = require('crypto');
// Replace with a structured logger (Winston, Pino, etc) in production
const logger = console;

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) {
    logger.error('Webhook error', { message: error.message });
    res.status(400).json({error: 'Webhook verification failed'});
  }
});
```

## Testing

### Sandbox Environment

The sandbox environment provides a complete testing environment that mirrors production:

```bash theme={null}
# 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 ${STATESET_API_KEY}
```

### Test Data

<Tabs>
  <Tab title="Test Cards">
    | Card Number           | Scenario           | Result                         |
    | --------------------- | ------------------ | ------------------------------ |
    | `4242 4242 4242 4242` | Successful payment | Always succeeds                |
    | `4000 0000 0000 0002` | Card declined      | Always fails                   |
    | `4000 0000 0000 9995` | Insufficient funds | Fails with insufficient\_funds |
    | `4000 0000 0000 0127` | Incorrect CVC      | Fails CVC check                |
  </Tab>

  <Tab title="Test Scenarios">
    ```javascript theme={null}
    // Test order scenarios
    const testScenarios = {
      // Successful order
      success: {
        customer_email: 'test-success@example.com',
        items: [{sku: 'TEST-SUCCESS', quantity: 1}]
      },
      
      // Inventory shortage
      out_of_stock: {
        customer_email: 'test-oos@example.com',
        items: [{sku: 'TEST-OOS', quantity: 1}]
      },
      
      // Payment failure
      payment_fail: {
        customer_email: 'test-fail@example.com',
        payment: {test_mode: 'fail'}
      }
    };
    ```
  </Tab>

  <Tab title="Webhook Testing">
    Use the webhook simulator to test your endpoint:

    ```bash theme={null}
    # Trigger test webhook
    curl -X POST https://api.sandbox.stateset.com/v1/webhooks/simulate \
      -H "Authorization: Bearer sk_test_..." \
      -d event_type="order.created" \
      -d endpoint_url="https://your-app.com/webhooks"
    ```
  </Tab>
</Tabs>

### Idempotency

StateSet API supports idempotency for safely retrying requests without side effects:

<Note>
  **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`)
</Note>

```bash theme={null}
# 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
```

```javascript theme={null}
// 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

| Plan           | Requests/Min | Requests/Day | Burst Limit | Concurrent Connections |
| -------------- | ------------ | ------------ | ----------- | ---------------------- |
| **Free**       | 60           | 1,000        | 100/sec     | 10                     |
| **Starter**    | 100          | 10,000       | 200/sec     | 25                     |
| **Growth**     | 1,000        | 100,000      | 1,000/sec   | 100                    |
| **Scale**      | 5,000        | 500,000      | 5,000/sec   | 500                    |
| **Enterprise** | Custom       | Unlimited    | Custom      | Unlimited              |

### Resource Limits

| Resource          | Limit       | Notes                                |
| ----------------- | ----------- | ------------------------------------ |
| Max request size  | 10 MB       | Increase available for Enterprise    |
| Max response size | 50 MB       | Paginate for larger datasets         |
| Webhook timeout   | 30 seconds  | Retry up to 3 times                  |
| File upload size  | 100 MB      | Direct upload to S3 for larger files |
| Batch operations  | 1,000 items | Use async jobs for larger batches    |

## Support and Community

<CardGroup cols={3}>
  <Card title="API Support" icon="envelope" href="mailto:api-support@stateset.com">
    Get help with integration issues
  </Card>

  <Card title="Discord Community" icon="discord" href="https://discord.gg/VfcaqgZywq">
    Join our developer community
  </Card>

  <Card title="Status Page" icon="chart-line" href="https://status.stateset.com">
    Check API status and uptime
  </Card>
</CardGroup>

### Additional Resources

* [API Changelog](/api-reference/changelog) - Latest updates and changes
* [Postman Collection](https://www.postman.com/stateset/workspace/stateset-api) - Ready-to-use API collection
* [OpenAPI Specification](/spec/openapi.yaml) - Machine-readable API spec
* [Code Examples](https://github.com/stateset/examples) - Sample implementations

***

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