Authentication & API Signatures
Every request to the Xeni API must include a valid signature in the Authorization header. This applies to all API products — Hotels, Cars, Flights, Activities, Resorts, Deals, and Content. Signatures are generated using your API key and secret, and expire after 30 minutes. This article covers how to generate, use, and refresh signatures.
How Authentication Works
- You send your API key, secret, and a Unix timestamp to the signature generation endpoint.
- The API returns a signature (a signed JWT token).
- You include this signature in the
Authorizationheader of all subsequent API calls. - When the signature is about to expire, you generate a new one.
Generating a Signature
Endpoint
POST /identity/v2/auth/generate
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
api_key | string | Yes | Your Xeni API key. |
secret | string | Yes | Your Xeni API secret. |
timestamp | integer | Yes | Current Unix timestamp in seconds (not milliseconds). |
Example Request
POST https://api.travelapi.ai/identity/v2/auth/generateContent-Type: application/json
{ "api_key": "eb8c1638-7fde-48f3-98fe-7ea8d06327d7", "secret": "your-secret-here", "timestamp": 1700000000}
Example Response
{
"signature": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}Using the Signature
Pass the signature as the value of the Authorization header on every API call:
GET /api/v2/{product}/endpoint
Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
Signature Expiration
Signatures are valid for 30 minutes from the time they are generated. After that, any API call using an expired signature will return an authentication error.
Recommended: Auto-Refresh Strategy
To avoid disruptions during active sessions, we recommend refreshing your signature proactively rather than waiting for it to expire. A common pattern:
- Store the signature and the time it was generated.
- Check the signature age before each API call (or on a recurring timer).
- If the signature has fewer than 5 minutes remaining, generate a new one.
Example: Auto-Refresh Logic (JavaScript)
class SignatureManager { constructor(apiKey, secret, baseUrl) { this.apiKey = apiKey; this.secret = secret; this.baseUrl = baseUrl; this.signature = null; this.expiresAt = null; }
async generateSignature() { const response = await fetch(${this.baseUrl}/identity/v2/auth/generate, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ api_key: this.apiKey, secret: this.secret, timestamp: Math.floor(Date.now() / 1000) }) });
const data = await response.json(); this.signature = data.signature; this.expiresAt = Date.now() + (30 60 1000); // 30 minutes return this.signature; }
needsRefresh() { if (!this.signature || !this.expiresAt) return true; // Refresh if less than 5 minutes remaining return (this.expiresAt - Date.now()) < (5 60 1000); }
async getSignature() { if (this.needsRefresh()) { await this.generateSignature(); } return this.signature; }}
Example: Auto-Refresh Logic (Python)
import timeimport requests
class SignatureManager: def init(self, apikey, secret, baseurl): self.apikey = apikey self.secret = secret self.baseurl = baseurl self.signature = None self.expires_at = 0
def generatesignature(self): response = requests.post( f"{self.baseurl}/identity/v2/auth/generate", json={ "apikey": self.apikey, "secret": self.secret, "timestamp": int(time.time()) } ) data = response.json() self.signature = data["signature"] self.expires_at = time.time() + (30 * 60) # 30 minutes return self.signature
def needsrefresh(self): if not self.signature: return True return (self.expiresat - time.time()) < (5 * 60) # 5-min threshold
def getsignature(self): if self.needsrefresh(): self.generate_signature() return self.signature
Common Authentication Errors
| HTTP Status | Cause | Resolution |
|---|---|---|
401 | Missing or invalid Authorization header | Ensure you're including the signature in the header. |
401 | Expired signature | Generate a new signature. Signatures expire after 30 minutes. |
401 | Invalid API key or secret | Verify your credentials are correct and active. |
400 | Timestamp is too far from server time | Ensure your system clock is accurate. Use Math.floor(Date.now() / 1000) or equivalent. |
Security Best Practices
- Never expose your API secret in client-side code. All signature generation should happen server-side.
- Store credentials securely. Use environment variables or a secrets manager — never hard-code credentials in source files.
- Rotate secrets regularly. Contact your Xeni account representative to rotate your API secret.
- Monitor for 401 errors. A spike in authentication failures may indicate compromised credentials.