Skip to main content

Overview

The Handshake endpoint is called every time a user opens the supplies module in your platform. It authenticates the user and returns a secure, time-limited session token that you use to embed the Sticker iframe.

When to Call This Endpoint

1

User Clicks Supplies

User navigates to the supplies/procurement section in your platform
2

Get Current User

Identify the authenticated user from your session
3

Call Handshake API

Send user identifier to receive a session token
4

Embed iframe

Display the iframe using the returned URL

API Endpoint

POST /v1/partner/handshake
Base URL: https://api.usesticker.com

Authentication

Use the X-API-Key header (not Authorization: Bearer):
X-API-Key: sk_live_your_api_key_here

Request Format

Send either internal_user_id OR profile_id:
{
  "internal_user_id": "user-789"
}
OR:
{
  "profile_id": "660f9500-f30c-52e5-b827-557766551111"
}
Recommended: Use internal_user_id (your internal identifier from organization setup). This way you don’t need to store Sticker profile IDs in your database.

Response Format

{
  "success": true,
  "session_key": "a1b2c3d4e5f6789012345678901234567890123456789012345678901234",
  "iframe_embed_url": "https://shop.usesticker.com/embedded/550e8400-e29b-41d4-a716-446655440000?session_key=a1b2c3d4e5f6789012345678901234567890123456789012345678901234",
  "expires_at": "2024-01-15T10:35:00.000Z",
  "profile": {
    "id": "660f9500-f30c-52e5-b827-557766551111",
    "first_name": "Jane",
    "last_name": "Smith",
    "email": "jane@acmemedical.com"
  }
}

Response Fields

FieldDescription
session_key64-char hex token for authentication
iframe_embed_urlComplete URL to embed—use this directly!
expires_atWhen the token expires (5 minutes from creation)
profileBasic info about the authenticated user

Session Token Properties

Session tokens have important security properties:
PropertyDescription
Single-useToken is invalidated after first use
5 minute expiryToken expires 5 minutes after creation
User-boundTied to a specific user profile
Partner-boundCan only be used with your partner iframe
Never reuse session tokens. Generate a new one each time the user opens supplies, even if they closed it seconds ago.

Complete Flow Example

Here’s what a typical integration looks like:

Code Examples

Your Backend Endpoint

app.post('/api/supplies/auth', async (req, res) => {
  const { userId } = req.body;
  
  // Verify user is authenticated in YOUR system
  const currentUser = await getAuthenticatedUser(req);
  if (!currentUser || currentUser.id !== userId) {
    return res.status(401).json({ error: 'Unauthorized' });
  }
  
  // Call Sticker handshake
  const response = await fetch('https://api.usesticker.com/v1/partner/handshake', {
    method: 'POST',
    headers: {
      'X-API-Key': process.env.STICKER_API_KEY,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      internal_user_id: userId
    })
  });
  
  if (!response.ok) {
    const error = await response.json();
    console.error('Handshake failed:', error);
    return res.status(response.status).json({ error: 'Authentication failed' });
  }
  
  const data = await response.json();
  
  // Return the iframe URL to your frontend
  res.json({
    iframe_url: data.iframe_embed_url,
    expires_at: data.expires_at
  });
});

Your Frontend Component

// React component that loads the supplies iframe
import { useState, useEffect } from 'react';

function SuppliesModule({ userId }) {
  const [iframeUrl, setIframeUrl] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    async function authenticate() {
      try {
        setLoading(true);
        setError(null);
        
        // Call YOUR backend (not Sticker directly!)
        const response = await fetch('/api/supplies/auth', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ userId })
        });
        
        if (!response.ok) {
          throw new Error('Failed to authenticate');
        }
        
        const { iframe_url } = await response.json();
        setIframeUrl(iframe_url);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    }
    
    authenticate();
  }, [userId]);

  if (loading) return <LoadingSpinner />;
  if (error) return <ErrorMessage error={error} onRetry={() => window.location.reload()} />;

  return (
    <iframe
      src={iframeUrl}
      className="w-full h-full border-0"
      title="Sticker Embedded Procurement"
      sandbox="allow-same-origin allow-scripts allow-forms allow-popups allow-popups-to-escape-sandbox allow-top-navigation-by-user-activation"
      allow="payment; publickey-credentials-get; fullscreen"
    />
  );
}

Error Handling

{
  "error": "Invalid request body",
  "details": [
    {
      "message": "Either internal_user_id or profile_id must be provided"
    }
  ]
}
Solution: Include either internal_user_id or profile_id in the request body.
{
  "error": "Unauthorized",
  "message": "Invalid or missing API key"
}
Solution: Check X-API-Key header (not Authorization: Bearer)
{
  "error": "Profile not found",
  "details": "No profile found with the provided credentials for this partner"
}
Solution:
  • Ensure organization setup was called first
  • Verify the internal_user_id matches what was used in setup
  • Check you’re using the correct partner API key
{
  "error": "Profile not set up for authentication",
  "details": "Profile must be linked to an auth user. Please complete setup first."
}
Solution: Contact Sticker support—the profile exists but isn’t properly linked.

Best Practices

Create tokens only when the user clicks to open supplies. Don’t pre-generate or cache tokens.
Always call the handshake from your backend. Never expose your API key in frontend code.
✅ Frontend → Your Backend → Sticker API
❌ Frontend → Sticker API directly
If a user takes too long to load the page (>5 min), generate a fresh token:
// Track when token was generated
const tokenGeneratedAt = Date.now();

// On iframe error, check if token might be expired
if (Date.now() - tokenGeneratedAt > 4 * 60 * 1000) {
  // Token is probably expired, get a new one
  await reauthenticate();
}
If the iframe fails to load, show a retry button that generates a new token:
if (error) {
  return (
    <div>
      <p>Failed to load supplies</p>
      <button onClick={authenticate}>Retry</button>
    </div>
  );
}
Authenticated Sticker

Testing

Test the handshake flow:
  1. Setup a test user via organization setup endpoint
  2. Call handshake with the test user’s internal_user_id
  3. Verify response contains valid iframe_embed_url
  4. Open the URL in a browser to confirm authentication works
# Test the handshake
curl -X POST https://api.usesticker.com/v1/partner/handshake \
  -H "X-API-Key: sk_test_your_key" \
  -H "Content-Type: application/json" \
  -d '{"internal_user_id": "test-user-123"}'

Next Steps