Skip to main content

Overview

Sticker uses API Key authentication to secure all partner API requests. Your API key identifies your partner account and authorizes access to your organizations and users.

API Key Authentication

Getting Your API Key

Contact the Sticker team to receive your API credentials:
  • Partner ID (UUID) - Your unique partner identifier
  • API Key (string) - Starts with sk_live_ or sk_test_
# Store securely in your environment
STICKER_PARTNER_ID=550e8400-e29b-41d4-a716-446655440000
STICKER_API_KEY=sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Keep your API key secret! Never expose it in client-side code, public repositories, or browser network requests.

Authentication Headers

Organization Setup Endpoint

Use the Authorization: Bearer header:
const response = await fetch('https://api.usesticker.com/v1/organizations/setup', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.STICKER_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ /* ... */ })
});

Partner Handshake Endpoint

Use the X-API-Key header:
const response = await fetch('https://api.usesticker.com/v1/partner/handshake', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.STICKER_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ /* ... */ })
});

API Environments

EnvironmentBase URLKey Prefix
Productionhttps://api.usesticker.com/v1sk_live_
Staging/Sandboxhttps://api.staging.usesticker.com/v1sk_test_
Use sandbox credentials for development and testing. Sandbox data is isolated from production.

Security Best Practices

Never expose your API key in client-side code.Your backend should:
  1. Receive requests from your frontend
  2. Make authenticated requests to Sticker API
  3. Return results to your frontend
// ❌ BAD - API key exposed in browser
const response = await fetch('https://api.usesticker.com/v1/partner/handshake', {
  headers: { 'X-API-Key': 'sk_live_xxx' }
});

// ✅ GOOD - API call goes through your backend
const response = await fetch('/api/supplies/auth', {
  method: 'POST',
  body: JSON.stringify({ userId: user.id })
});
Store API keys in environment variables, never in code:
# .env (never commit this file)
STICKER_API_KEY=sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// Read from environment
const apiKey = process.env.STICKER_API_KEY;
If you suspect your API key has been compromised:
  1. Contact Sticker support immediately
  2. We’ll issue a new key
  3. Update your environment variables
  4. Redeploy your application
Old keys are invalidated immediately upon rotation.
Sticker logs all API requests with:
  • Timestamp
  • Partner ID
  • Endpoint called
  • Response status
  • IP address
Contact support to review your API activity.

Error Responses

401 Unauthorized

Returned when authentication fails:
{
  "error": "Unauthorized",
  "message": "Invalid or missing API key",
  "code": "UNAUTHORIZED"
}
Common causes:
  • Missing Authorization or X-API-Key header
  • Invalid or expired API key
  • Using production key in sandbox or vice versa

403 Forbidden

Returned when authenticated but not authorized:
{
  "error": "Forbidden",
  "message": "API key does not have required scope",
  "code": "FORBIDDEN"
}
Common causes:
  • API key lacks required permissions/scope
  • Trying to access resources belonging to another partner

Session Tokens

When users access the embedded iframe, they use session tokens instead of API keys. Session tokens are:
PropertyDescription
Short-livedExpire after 5 minutes
Single-useInvalidated after first use
User-boundTied to a specific user profile
Secure64-character cryptographically random hex strings
// Generate session token via handshake
const { session_key, iframe_embed_url } = await handshake(userId);

// Session token is embedded in iframe URL
// https://shop.usesticker.com/embedded/{partner_id}?session_key={token}
Never reuse session tokens. Generate a fresh token every time a user opens the supplies module.

Rate Limits

EndpointRate Limit
/v1/organizations/setup100 requests/minute
/v1/partner/handshake300 requests/minute
When rate limited, you’ll receive a 429 Too Many Requests response:
{
  "error": "Rate limit exceeded",
  "code": "RATE_LIMIT_EXCEEDED",
  "retry_after": 60
}
Implement exponential backoff for retries:
async function withRetry(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (error.status === 429 && i < maxRetries - 1) {
        const delay = Math.pow(2, i) * 1000;
        await new Promise(r => setTimeout(r, delay));
        continue;
      }
      throw error;
    }
  }
}

Testing Authentication

Verify your authentication is working:
# Test with curl
curl -X POST https://api.usesticker.com/v1/partner/handshake \
  -H "X-API-Key: sk_test_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"internal_user_id": "test-user-123"}'
Expected response (if user exists):
{
  "success": true,
  "session_key": "abc123...",
  "iframe_embed_url": "https://shop.usesticker.com/embedded/...",
  "expires_at": "2024-01-15T10:35:00.000Z",
  "profile": {
    "id": "550e8400-...",
    "first_name": "Test",
    "last_name": "User",
    "email": "test@example.com"
  }
}

Next Steps