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 application.
When to Call This Endpoint
User Navigation
User clicks on “Supplies” or similar navigation item in your platform
Identify User
Get the current authenticated user’s details from your session
Call Handshake API
Send user information to receive a session token
Embed iframe
Display the iframe with the session token in the URL
API Endpoint
POST /api/partner/handshake
Base URL: https://api.sticker.com (production) or https://sandbox.api.sticker.com (sandbox)
Authentication
This endpoint requires both API key authentication and request signing:
headers : {
'Authorization' : 'Bearer sk_live_your_api_key' ,
'Content-Type' : 'application/json' ,
'X-Partner-Signature' : 'sha256=hmac_digest_here'
}
The handshake endpoint requires HMAC-SHA256 request signing for security. See the Authentication Guide for details.
{
"partner_org_id" : "your_internal_org_id" ,
"user" : {
"email" : "dr.smith@acmemedical.com" ,
"first_name" : "John" ,
"last_name" : "Smith"
}
}
Request Parameters
Your internal identifier for the organization. This must match the ID used during organization setup.
The user’s email address. Must match an email in the organization’s user list.
The user’s first name (used to update profile if changed)
The user’s last name (used to update profile if changed)
Generating Request Signatures
The handshake endpoint requires an HMAC-SHA256 signature to verify request authenticity:
Signature Algorithm
Serialize Request Body
Convert your request to a JSON string (no pretty printing) const requestBody = JSON . stringify ({
partner_org_id: 'org_123' ,
user: {
email: 'user@example.com' ,
first_name: 'John' ,
last_name: 'Doe'
}
});
Create HMAC Digest
Hash the request body using your API key as the secret const crypto = require ( 'crypto' );
const hmac = crypto
. createHmac ( 'sha256' , process . env . STICKER_API_KEY )
. update ( requestBody )
. digest ( 'hex' );
Format Signature
Add the “sha256=” prefix const signature = `sha256= ${ hmac } ` ;
Add to Headers
Include in the X-Partner-Signature header headers : {
'X-Partner-Signature' : signature
}
Complete Signing Example
const crypto = require ( 'crypto' );
function generateSignature ( requestBody , apiKey ) {
const hmac = crypto
. createHmac ( 'sha256' , apiKey )
. update ( requestBody )
. digest ( 'hex' );
return `sha256= ${ hmac } ` ;
}
async function handshakeUser ( orgId , user ) {
const requestBody = JSON . stringify ({
partner_org_id: orgId ,
user: {
email: user . email ,
first_name: user . firstName ,
last_name: user . lastName
}
});
const signature = generateSignature (
requestBody ,
process . env . STICKER_API_KEY
);
const response = await fetch ( 'https://api.sticker.com/api/partner/handshake' , {
method: 'POST' ,
headers: {
'Authorization' : `Bearer ${ process . env . STICKER_API_KEY } ` ,
'Content-Type' : 'application/json' ,
'X-Partner-Signature' : signature
},
body: requestBody
});
if ( ! response . ok ) {
const error = await response . json ();
throw new Error ( `Handshake failed: ${ error . error } ` );
}
return await response . json ();
}
Success Response (200 OK)
{
"success" : true ,
"session_key" : "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6" ,
"iframe_url" : "https://app.sticker.com/embed" ,
"expires_in" : 300
}
Whether the handshake succeeded
Secure, time-limited token for authenticating the user in the iframe. Single-use only.
Base URL for embedding Sticker. Append ?session_key={session_key} to this URL.
Time in seconds until the session token expires (default: 300 seconds / 5 minutes)
Error Responses
{
"error" : "Missing required field: user.email" ,
"code" : "INVALID_REQUEST"
}
Common causes:
Missing required fields (partner_org_id, user.email, etc.)
Invalid email format
Malformed request body
{
"error" : "Invalid signature" ,
"code" : "INVALID_SIGNATURE"
}
Solution: Verify your HMAC signature is generated correctly using the exact request body
{
"error" : "No profile found with partner_org_id: org_123" ,
"code" : "ORGANIZATION_NOT_FOUND"
}
Solution: Ensure the organization was set up via the organization-setup endpoint first
{
"error" : "User not authorized for this organization" ,
"code" : "USER_NOT_FOUND"
}
Solution: The user email doesn’t exist in this organization. Add the user via organization-setup endpoint.
{
"error" : "Rate limit exceeded" ,
"code" : "RATE_LIMIT_EXCEEDED" ,
"retry_after" : 60
}
Solution: Implement exponential backoff and retry after the specified seconds
Session Token Properties
Understanding session tokens is crucial for secure integration:
Single-Use Each token can only be used once to authenticate
Time-Limited Tokens expire 5 minutes after generation
User-Specific Tokens are tied to a specific user and organization
Secure Cryptographically random, 64-character hex string
Never reuse session tokens. Generate a new token each time the user opens the supplies module, even if they just closed it seconds ago.
Using the Session Token
After receiving the session token, append it to the iframe URL:
< iframe
src = "https://app.sticker.com/embed?session_key=a1b2c3d4e5f6g7h8i9j0..."
width = "100%"
height = "800px"
frameborder = "0"
/ >
See the iframe Embedding Guide for complete implementation details.
Handling Name Updates
The handshake endpoint automatically updates user profiles if names have changed:
// User changed their name in your system
const updatedUser = {
email: 'dr.smith@acmemedical.com' ,
first_name: 'Jonathan' , // Changed from 'John'
last_name: 'Smith'
};
// Next handshake will update the name in Sticker
const result = await handshakeUser ( orgId , updatedUser );
Sticker automatically syncs user first and last names on each handshake. Email addresses cannot be changed (they’re the unique identifier).
Session Management Best Practices
Create session tokens only when the user clicks to open the supplies module, not in advance.
If a user takes more than 5 minutes to load the page, generate a fresh token.
Don’t cache or store session tokens. They’re single-use and short-lived.
If iframe fails to load, generate a new token and retry.
Show loading states while generating tokens and embedding the iframe.
Complete Integration Example
Here’s a full implementation including error handling and loading states:
import { useState , useEffect } from 'react' ;
function SuppliesModule ({ user , organizationId }) {
const [ sessionKey , setSessionKey ] = useState ( null );
const [ loading , setLoading ] = useState ( true );
const [ error , setError ] = useState ( null );
useEffect (() => {
async function authenticate () {
try {
setLoading ( true );
setError ( null );
// Call your backend to get session token
const response = await fetch ( '/api/supplies/authenticate' , {
method: 'POST' ,
headers: { 'Content-Type' : 'application/json' },
body: JSON . stringify ({
org_id: organizationId ,
user: {
email: user . email ,
first_name: user . firstName ,
last_name: user . lastName
}
})
});
if ( ! response . ok ) {
throw new Error ( 'Authentication failed' );
}
const data = await response . json ();
setSessionKey ( data . session_key );
} catch ( err ) {
setError ( err . message );
} finally {
setLoading ( false );
}
}
authenticate ();
}, [ user , organizationId ]);
if ( loading ) {
return < div > Loading supplies... </ div > ;
}
if ( error ) {
return (
< div >
< p > Failed to load supplies: { error } </ p >
< button onClick = { () => window . location . reload () } >
Retry
</ button >
</ div >
);
}
return (
< iframe
src = { `https://app.sticker.com/embed?session_key= ${ sessionKey } ` }
width = "100%"
height = "800px"
frameBorder = "0"
allow = "payment"
sandbox = "allow-same-origin allow-scripts allow-forms allow-popups"
style = { { border: 'none' } }
/>
);
}
Testing
Test your handshake implementation in the sandbox:
# Sandbox endpoint
POST https://sandbox.api.sticker.com/api/partner/handshake
# Test with a previously created organization
{
"partner_org_id" : "test_org_123",
"user" : {
"email" : "test@example.com",
"first_name" : "Test",
"last_name" : "User"
}
}
Use browser DevTools Network tab to inspect handshake requests and verify signatures are being generated correctly.
Next Steps