Skip to main content

Overview

This guide provides step-by-step instructions for setting up authentication with Zupy’s loyalty APIs. You’ll learn how to verify your partner account, generate secure API keys, and implement authentication in your application.
Prerequisites: Active Zupy partner account with developer dashboard access

Step 1: Account Verification & Dashboard Access

Access Your Developer Dashboard

Navigate to the Zupy developer dashboard to begin the authentication setup process:
https://app.zupy.com/developers/api-keys
If you don’t see the developer section in your dashboard, contact our partner team at [email protected] to enable developer access for your account.

Partner Account Requirements

Your partner account must have:

Verified Business Information

Company name, CNPJ, and business address verified

Active Partnership Agreement

Signed partnership agreement with Zupy platform

Verified Contact Information

WhatsApp number and email address verified for OTP delivery

Step 2: OTP Verification Process

Before generating API keys, you must complete identity verification using our One-Time Password (OTP) system.

WhatsApp OTP Verification (Primary Method)

1

Initiate Verification

Click “Verify Account” or “Generate API Key” in your dashboard
2

Request OTP

Select “Send via WhatsApp” for OTP deliveryImportant: Use the same WhatsApp number registered with your partner account
3

Receive Code

Check your WhatsApp for a message like:
Zupy Developer Verification

Your verification code: 123456

This code expires in 5 minutes.
Do not share this code with anyone.
4

Enter Code

Input the 6-digit code in the verification dialog within 5 minutes
5

Confirmation

Successful verification enables API key generation for 24 hours

Email OTP Verification (Backup Method)

If WhatsApp verification fails or is unavailable:
1

Select Email Option

Click “Send via Email” in the verification dialog
2

Check Email

Look for an email from [email protected] with subject “Zupy Developer Verification”Check spam folder if the email doesn’t arrive within 2 minutes
3

Enter Email Code

Email codes are valid for 10 minutes and follow the same 6-digit format

Troubleshooting OTP Issues

WhatsApp Issues:
  • Verify your registered WhatsApp number is correct in your partner profile
  • Ensure WhatsApp Business API messages aren’t blocked on your device
  • Check if your WhatsApp is connected to the internet
  • Try requesting email OTP as an alternative
Email Issues:
  • Check spam/junk folders for the verification email
  • Verify the email address in your partner profile is correct
  • Ensure emails from zupy.com domain aren’t blocked by your email provider
  • Check email filtering rules that might redirect Zupy emails
General Solutions:
  • Wait 60 seconds before requesting a new code to avoid rate limiting
  • Clear browser cache and cookies if the verification dialog isn’t working
  • Try using an incognito/private browser window
  • Contact support at [email protected] if issues persist
Common Causes:
  • WhatsApp codes expire after 5 minutes
  • Email codes expire after 10 minutes
  • Code was already used successfully
  • Browser session timed out during verification
Solutions:
  1. Request a new OTP code using the same method
  2. Complete verification within the time limit
  3. Use the most recently received code (previous codes become invalid)
  4. Refresh the browser page if the verification dialog is unresponsive
Possible Issues:
  • Code was mistyped (common with similar-looking numbers)
  • Code has expired
  • Using an old code when a new one was requested
  • Browser autofill entered incorrect information
Solutions:
  • Double-check each digit of the code
  • Ensure you’re using the most recent code received
  • Manually type the code instead of copy-pasting
  • Request a fresh code if the current one isn’t working

Step 3: API Key Generation

After successful OTP verification, you can generate API keys for your integrations.

Development/Staging Keys

Start with staging keys for development and testing:
{
  "name": "Development Integration",
  "environment": "staging",
  "permissions": [
    "customer:read",
    "customer:write",
    "loyalty:read", 
    "loyalty:write",
    "coupons:validate",
    "coupons:redeem"
  ],
  "rate_limit": 500,
  "description": "Key for development and testing"
}
Key Properties:
  • Environment: staging for development, production for live use
  • Rate Limit: 500 requests/minute recommended for staging
  • Permissions: Include all permissions you’ll need for testing

Production Keys

For production deployment, create keys with minimal necessary permissions:
{
  "name": "Production PDV Integration", 
  "environment": "production",
  "permissions": [
    "customer:read",
    "customer:write",
    "loyalty:read",
    "coupons:validate", 
    "coupons:redeem"
  ],
  "rate_limit": 1000,
  "ip_restrictions": [
    "203.0.113.0/24",  // Your office network
    "198.51.100.15"    // Production server IP
  ],
  "expires_at": "2025-12-31T23:59:59Z"
}
Production Best Practices:
  • Minimal Permissions: Only include permissions your application actually uses
  • IP Restrictions: Limit access to known IP addresses or networks
  • Expiration: Set reasonable expiration dates (6-12 months)
  • Higher Rate Limits: Request higher limits for production traffic

API Key Response Format

When you generate an API key, you’ll receive a response like this:
{
  "api_key": "zup_test_sk_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
  "key_id": "key_abc123def456", 
  "name": "Development Integration",
  "environment": "staging",
  "permissions": [
    "customer:read",
    "customer:write", 
    "loyalty:read",
    "loyalty:write",
    "coupons:validate",
    "coupons:redeem"
  ],
  "rate_limit": 500,
  "ip_restrictions": [],
  "created_at": "2025-09-04T10:30:00Z",
  "expires_at": "2026-09-04T10:30:00Z",
  "last_used_at": null,
  "usage_count": 0
}
Security Critical: The api_key value is only shown once during generation. Copy and store it securely immediately.

Step 4: Secure Key Storage

Store API keys as environment variables, never in source code:
# Zupy API Configuration
ZUPY_API_KEY=zup_test_sk_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
ZUPY_BASE_URL=https://api-staging.zupy.com/v1
ZUPY_COMPANY_ID=your_company_identifier

# Production values (use separate .env.production)
# ZUPY_API_KEY=zup_live_sk_production_key_here
# ZUPY_BASE_URL=https://api.zupy.com/v1

Docker/Container Deployment

For containerized applications, pass environment variables at runtime:
version: '3.8'
services:
  your-app:
    image: your-app:latest
    environment:
      - ZUPY_API_KEY=${ZUPY_API_KEY}
      - ZUPY_BASE_URL=${ZUPY_BASE_URL}
      - ZUPY_COMPANY_ID=${ZUPY_COMPANY_ID}
    env_file:
      - .env.production

Key Rotation Strategy

Implement regular key rotation for enhanced security:
1

Generate New Key

Create a new API key with identical permissions to the current one
2

Update Configuration

Update your application configuration with the new key
3

Deploy Changes

Deploy the updated configuration to all environments
4

Test New Key

Verify the new key works correctly with a test API call
5

Monitor Usage

Check API key usage statistics in the dashboard
6

Revoke Old Key

After confirming the new key works, revoke the previous key
Recommended Rotation Schedule:
  • Development Keys: Every 90 days
  • Production Keys: Every 60 days
  • High-Security Environments: Every 30 days

Step 5: Implementation & Testing

Basic Authentication Implementation

Implement API authentication in your application:
class ZupyAuthentication {
  constructor(apiKey, baseUrl) {
    this.apiKey = apiKey;
    this.baseUrl = baseUrl.replace(/\/$/, ''); // Remove trailing slash
    this.headers = {
      'Authorization': `Bearer ${apiKey}`,
      'Content-Type': 'application/json',
      'User-Agent': 'YourApp/1.0.0'
    };
  }

  async makeRequest(endpoint, options = {}) {
    const url = `${this.baseUrl}${endpoint}`;
    
    const config = {
      ...options,
      headers: {
        ...this.headers,
        ...options.headers
      }
    };

    try {
      const response = await fetch(url, config);
      
      // Check for authentication errors
      if (response.status === 401) {
        throw new Error('Authentication failed: Invalid or expired API key');
      }
      
      if (response.status === 403) {
        throw new Error('Permission denied: API key lacks required permissions');
      }
      
      if (response.status === 429) {
        const retryAfter = response.headers.get('X-RateLimit-Reset');
        throw new Error(`Rate limit exceeded. Retry after: ${retryAfter}`);
      }
      
      if (!response.ok) {
        const errorData = await response.json().catch(() => null);
        throw new Error(`API Error ${response.status}: ${errorData?.message || response.statusText}`);
      }
      
      return await response.json();
    } catch (error) {
      console.error('Zupy API Error:', error);
      throw error;
    }
  }

  // Test authentication
  async testConnection() {
    try {
      const result = await this.makeRequest('/loyalty/program');
      console.log('✅ Authentication successful');
      return { success: true, program: result };
    } catch (error) {
      console.error('❌ Authentication failed:', error.message);
      return { success: false, error: error.message };
    }
  }
}

// Usage
const zupy = new ZupyAuthentication(
  process.env.ZUPY_API_KEY,
  process.env.ZUPY_BASE_URL
);

// Test authentication on startup
zupy.testConnection().then(result => {
  if (!result.success) {
    console.error('Failed to authenticate with Zupy API');
    process.exit(1);
  }
});

Authentication Testing

Test your authentication implementation with these verification steps:
# Test with your API key
curl -X GET "https://api-staging.zupy.com/v1/loyalty/program" \
  -H "Authorization: Bearer zup_test_sk_YOUR_KEY" \
  -H "Content-Type: application/json"

# Expected: 200 OK with program configuration
# Test with invalid key to verify error handling
curl -X GET "https://api-staging.zupy.com/v1/loyalty/program" \
  -H "Authorization: Bearer invalid_key_12345" \
  -H "Content-Type: application/json"

# Expected: 401 Unauthorized with error message
# Test without authorization header
curl -X GET "https://api-staging.zupy.com/v1/loyalty/program" \
  -H "Content-Type: application/json"

# Expected: 401 Unauthorized
// Test endpoint requiring specific permissions
const customer = await zupy.makeRequest('/loyalty/customers', {
  method: 'POST',
  body: JSON.stringify({
    whatsapp: '+5511999888777',
    name: 'Test Customer',
    integration_source: 'test',
    company_id: 'your_company_id'
  })
});

// If successful: Customer created
// If permission error: 403 Forbidden with specific permission needed

Step 6: Monitoring & Maintenance

API Key Usage Monitoring

Monitor your API key usage through the developer dashboard: Key Metrics to Track:
  • Request Volume: Daily/hourly request counts
  • Error Rates: Authentication failures and permission errors
  • Rate Limiting: How close you’re getting to limits
  • Last Used: When the key was last accessed

Health Checks

Implement regular health checks for your authentication:
class ZupyHealthCheck {
  constructor(zupyAuth) {
    this.zupy = zupyAuth;
    this.lastCheck = null;
    this.healthStatus = null;
  }

  async performHealthCheck() {
    try {
      const startTime = Date.now();
      const result = await this.zupy.makeRequest('/loyalty/program');
      const responseTime = Date.now() - startTime;
      
      this.healthStatus = {
        healthy: true,
        responseTime: responseTime,
        timestamp: new Date().toISOString(),
        lastError: null
      };
      
      console.log(`✅ Zupy API healthy (${responseTime}ms)`);
      return this.healthStatus;
      
    } catch (error) {
      this.healthStatus = {
        healthy: false,
        responseTime: null,
        timestamp: new Date().toISOString(),
        lastError: error.message
      };
      
      console.error(`❌ Zupy API unhealthy: ${error.message}`);
      return this.healthStatus;
    }
  }

  // Schedule regular health checks
  startMonitoring(intervalMinutes = 5) {
    const interval = intervalMinutes * 60 * 1000;
    
    // Initial check
    this.performHealthCheck();
    
    // Regular checks
    setInterval(() => {
      this.performHealthCheck();
    }, interval);
  }
}

// Usage
const healthCheck = new ZupyHealthCheck(zupy);
healthCheck.startMonitoring(5); // Check every 5 minutes

Troubleshooting Common Issues

Symptoms: Random 401 errors despite valid API keyPossible Causes:
  • Network connectivity issues
  • DNS resolution problems
  • Clock synchronization issues
  • Firewall blocking API requests
Solutions:
  1. Implement retry logic with exponential backoff
  2. Check system clock synchronization
  3. Verify network connectivity to api.zupy.com
  4. Check firewall/proxy settings
Symptoms: 403 permission denied errors after generating new keyPossible Causes:
  • New key has different permissions than expected
  • Cached old key still being used
  • Application using wrong key for specific operations
Solutions:
  1. Compare new key permissions with old key in dashboard
  2. Clear application cache/restart services
  3. Verify environment variables are updated correctly
  4. Test each required permission individually
Symptoms: 429 rate limit exceeded errorsPossible Causes:
  • Application making too many requests too quickly
  • Multiple application instances using same key
  • Inefficient API usage patterns
Solutions:
  1. Implement request queuing/throttling
  2. Use separate keys for different application instances
  3. Cache API responses to reduce request volume
  4. Review API usage patterns for optimization opportunities

Next Steps

After completing authentication setup:

Integration Development

Follow the complete integration guide to build your loyalty program integration

API Reference

Explore detailed API documentation for all available endpoints

Webhook Setup

Configure webhooks for real-time event notifications

Support: Contact [email protected] if you encounter any issues during authentication setup or need assistance with API key configuration.