Authentication Guide

Authentication Guide

The Spreetail Channel Integration API uses JWT (JSON Web Token) Bearer token authentication. This guide explains how to authenticate your requests and manage tokens effectively.

Overview

All API endpoints (except /auth/login) require authentication using a Bearer token in the Authorization header. Tokens are obtained by calling the /auth/login endpoint with your Client ID and Client Secret.

Authentication Flow

1. Obtain Credentials

Contact [email protected] to receive:

  • Client ID: Your unique identifier (e.g., client-abc-123)
  • Client Secret: Your secret key (e.g., secret-xyz-789)
🔒

Never share your Client Secret publicly. Store it securely using environment variables or a secrets management system.

2. Request Access Token

Call the /auth/login endpoint with your credentials:

POST https://api.spreetaileu.com/api/api/v1/auth/login
Content-Type: application/json

{
  "client_id": "your-client-id",
  "client_secret": "your-client-secret"
}

Success Response (200):

{
  "success": true,
  "data": {
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "expires_in": 86400,
    "client_id": "your-client-id"
  }
}

Error Response (401):

{
  "success": false,
  "error": "Invalid credentials"
}

3. Use the Token

Include the access token in the Authorization header for all subsequent requests:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Token Expiration

  • Token Validity: 24 hours (86,400 seconds)
  • Expiration Handling: When a token expires, you'll receive a 401 Unauthorized response
  • Token Refresh: Simply call /auth/login again to get a new token

Best Practices

Token Caching

Cache your access token and reuse it for all requests during its validity period:

import time
import requests

class SpreetailAPIClient:
    def __init__(self, client_id, client_secret):
        self.client_id = client_id
        self.client_secret = client_secret
        self.token = None
        self.token_expires_at = 0
        self.base_url = "https://api.spreetaileu.com/api/api/v1"
    
    def get_token(self):
        """Get a valid access token, refreshing if necessary"""
        if self.token and time.time() < self.token_expires_at:
            return self.token
        
        # Request new token
        response = requests.post(
            f"{self.base_url}/auth/login",
            json={
                "client_id": self.client_id,
                "client_secret": self.client_secret
            }
        )
        response.raise_for_status()
        data = response.json()
        
        if data['success']:
            self.token = data['data']['access_token']
            # Set expiration 5 minutes before actual expiry for safety
            self.token_expires_at = time.time() + data['data']['expires_in'] - 300
            return self.token
        else:
            raise Exception(f"Authentication failed: {data.get('error')}")
    
    def make_request(self, method, endpoint, **kwargs):
        """Make an authenticated API request"""
        token = self.get_token()
        headers = kwargs.get('headers', {})
        headers['Authorization'] = f'Bearer {token}'
        kwargs['headers'] = headers
        
        response = requests.request(
            method,
            f"{self.base_url}{endpoint}",
            **kwargs
        )
        return response

Error Handling

Always handle authentication errors gracefully:

def make_authenticated_request(client, endpoint, **kwargs):
    try:
        response = client.make_request('POST', endpoint, **kwargs)
        
        # Handle token expiration
        if response.status_code == 401:
            # Token might be expired, try refreshing
            client.token = None
            response = client.make_request('POST', endpoint, **kwargs)
        
        response.raise_for_status()
        return response.json()
    except requests.exceptions.HTTPError as e:
        if e.response.status_code == 401:
            raise Exception("Authentication failed. Check your credentials.")
        raise

Security Considerations

  1. Never Commit Secrets: Use environment variables or secure vaults
  2. Use HTTPS Only: All API requests must use HTTPS
  3. Rotate Secrets: Regularly rotate your Client Secret
  4. Monitor Token Usage: Log authentication failures for security monitoring
  5. Token Storage: Store tokens securely in memory, not in logs or files

Common Issues

Issue: "Invalid credentials" error

Possible Causes:

  • Incorrect Client ID or Client Secret
  • Credentials not activated
  • Account suspended

Solution:

  • Verify credentials with [email protected]
  • Check for typos in credentials
  • Ensure account is active

Issue: Token expires frequently

Solution:

  • Implement token caching as shown above
  • Refresh tokens proactively before expiration
  • Handle 401 errors by re-authenticating

Issue: "Unauthorized" on valid token

Possible Causes:

  • Token expired
  • Missing "Bearer " prefix in Authorization header
  • Token format incorrect

Solution:

  • Ensure header format: Authorization: Bearer <token>
  • Check token hasn't expired
  • Verify token is the full JWT string

Example: Complete Authentication Flow

import requests
import time

class SpreetailAPI:
    def __init__(self, client_id, client_secret):
        self.client_id = client_id
        self.client_secret = client_secret
        self.base_url = "https://api.spreetaileu.com/api/api/v1"
        self.token = None
        self.token_expires_at = 0
    
    def authenticate(self):
        """Authenticate and get access token"""
        response = requests.post(
            f"{self.base_url}/auth/login",
            json={
                "client_id": self.client_id,
                "client_secret": self.client_secret
            }
        )
        response.raise_for_status()
        data = response.json()
        
        if not data.get('success'):
            raise Exception(f"Authentication failed: {data.get('error')}")
        
        self.token = data['data']['access_token']
        self.token_expires_at = time.time() + data['data']['expires_in']
        return self.token
    
    def get_headers(self):
        """Get headers with authentication"""
        if not self.token or time.time() >= self.token_expires_at:
            self.authenticate()
        
        return {
            "Authorization": f"Bearer {self.token}",
            "Content-Type": "application/json"
        }
    
    def create_order(self, order_data):
        """Create an outbound order"""
        response = requests.post(
            f"{self.base_url}/outbound",
            headers=self.get_headers(),
            json=order_data
        )
        response.raise_for_status()
        return response.json()

# Usage
api = SpreetailAPI(
    client_id="your-client-id",
    client_secret="your-client-secret"
)

order = {
    "ReferenceNumber": "ORD-001",
    # ... rest of order data
}

result = api.create_order(order)
print(result)

Support

For authentication issues or to request credentials: