Quick Start: Get your API keys from the StateSet Dashboard and make your first authenticated request in minutes.

๐Ÿ” Overview

StateSet uses API keys to authenticate requests. Authentication is performed via HTTP headers using the Bearer token format. All API requests must be made over HTTPS.

๐Ÿ”‘ API Key Types

Test Mode

Prefix: sk_test_Use for development and testing. Transactions are simulated and no real money moves.

Live Mode

Prefix: sk_live_Use for production. All transactions are real and irreversible.
Never expose your secret API keys in client-side code, public repositories, or anywhere else accessible to the public.

๐Ÿ“‹ Authentication Methods

Standard Authentication

Include your API key in the Authorization header:
curl https://api.stateset.com/v1/account/balance \
  -H "Authorization: Bearer sk_test_4eC39HqLyjWDarjtT1zdp7dc"

SDK Authentication

When using our official SDKs, initialize with your API key:
import { StateSet } from '@stateset/sdk';

const stateset = new StateSet({
  apiKey: process.env.STATESET_API_KEY // Best practice: use environment variables
});

๐Ÿ›ก๏ธ Security Best Practices

๐Ÿ”’ Advanced Authentication

HMAC Signatures (High-Security Operations)

For sensitive operations like large transfers or issuance, add HMAC signatures:
const crypto = require('crypto');

function createHmacSignature(payload, secret) {
  const timestamp = Math.floor(Date.now() / 1000);
  const message = `${timestamp}.${JSON.stringify(payload)}`;
  
  const signature = crypto
    .createHmac('sha256', secret)
    .update(message)
    .digest('hex');
    
  return {
    signature,
    timestamp
  };
}

// Use in request
const payload = { amount: '10000.00', to: 'stateset1abc...' };
const { signature, timestamp } = createHmacSignature(payload, process.env.HMAC_SECRET);

const response = await axios.post('https://api.stateset.com/v1/stablecoin/transfer', payload, {
  headers: {
    'Authorization': `Bearer ${apiKey}`,
    'X-Signature': signature,
    'X-Timestamp': timestamp
  }
});

OAuth 2.0 (Partner Integrations)

For third-party integrations, use OAuth 2.0:
// 1. Redirect user to authorize
const authUrl = `https://auth.stateset.com/oauth/authorize?
  client_id=${CLIENT_ID}&
  redirect_uri=${REDIRECT_URI}&
  response_type=code&
  scope=payments:read+payments:write`;

// 2. Exchange code for token
const tokenResponse = await axios.post('https://auth.stateset.com/oauth/token', {
  grant_type: 'authorization_code',
  code: authorizationCode,
  client_id: CLIENT_ID,
  client_secret: CLIENT_SECRET,
  redirect_uri: REDIRECT_URI
});

// 3. Use access token
const response = await axios.get('https://api.stateset.com/v1/payments', {
  headers: {
    'Authorization': `Bearer ${tokenResponse.data.access_token}`
  }
});

๐Ÿ“Š Rate Limits

API keys have different rate limits based on your plan:
PlanRequests/SecondRequests/DayBurst Limit
Free101,00020
Starter100100,000200
Growth1,00010,000,0002,000
EnterpriseCustomCustomCustom

Handling Rate Limits

async function makeRequestWithRetry(url, options, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await axios.get(url, options);
      return response.data;
    } catch (error) {
      if (error.response?.status === 429) {
        const retryAfter = error.response.headers['retry-after'] || 2 ** i;
        console.log(`Rate limited. Retrying after ${retryAfter} seconds...`);
        await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
      } else {
        throw error;
      }
    }
  }
  throw new Error('Max retries exceeded');
}

๐Ÿšจ Error Responses

Authentication errors return standardized responses:
{
  "error": {
    "type": "authentication_error",
    "message": "Invalid API key provided",
    "code": "invalid_api_key",
    "status": 401
  }
}
Common authentication errors:
Error CodeDescriptionSolution
missing_api_keyNo API key providedInclude Authorization header
invalid_api_keyAPI key is invalidCheck key format and validity
expired_api_keyAPI key has expiredGenerate a new key
insufficient_permissionsKey lacks required permissionsUse a key with proper permissions
rate_limit_exceededToo many requestsImplement backoff and retry

๐Ÿ”„ Key Management API

Programmatically manage your API keys:
// List all keys
const keys = await stateset.apiKeys.list();

// Create a new key
const newKey = await stateset.apiKeys.create({
  name: 'Mobile App Key',
  permissions: ['payments:create', 'payments:read'],
  expires_at: '2024-12-31T23:59:59Z'
});

// Revoke a key
await stateset.apiKeys.revoke('key_abc123');

// Update key permissions
await stateset.apiKeys.update('key_abc123', {
  permissions: ['payments:read']
});

๐Ÿงช Testing Authentication

Use our test endpoint to verify your authentication:
curl https://api.stateset.com/v1/auth/test \
  -H "Authorization: Bearer sk_test_4eC39HqLyjWDarjtT1zdp7dc"
Success response:
{
  "authenticated": true,
  "key_id": "key_abc123",
  "permissions": ["payments:create", "payments:read"],
  "mode": "test"
}

๐Ÿ“ฑ Mobile & Frontend Security

Never use secret API keys in mobile apps or frontend code. Use our public keys or implement a backend proxy.

Public Keys (Read-Only Operations)

// Safe to use in frontend
const publicKey = 'pk_test_TYooMQauvdEDq54NiTphI7jx';

// Limited to read-only operations
const balance = await fetch(`https://api.stateset.com/v1/public/balance/${address}`, {
  headers: {
    'Authorization': `Bearer ${publicKey}`
  }
});

Backend Proxy Pattern

// Frontend
const response = await fetch('/api/stateset-proxy/payment', {
  method: 'POST',
  body: JSON.stringify({ amount: 100, recipient: 'stateset1abc...' })
});

// Backend (Node.js/Express)
app.post('/api/stateset-proxy/payment', authenticate, async (req, res) => {
  const payment = await stateset.payments.create({
    ...req.body,
    customer: req.user.id
  });
  res.json(payment);
});

๐Ÿ†˜ Troubleshooting

๐Ÿ“š Next Steps