Authentication
The BookingAPI uses service-account JWT authentication. You exchange an API key and secret
for a short-lived token, then pass that token as a Bearer header on every request.
Get your credentials
Contact your MoovLogic account manager to have a service account created. You will receive:
- An
apiKey— your account identifier (UUID format) - An
apiSecret— your secret credential
apiSecret in an environment variable or secrets manager. Never commit it to source control or expose it in client-side JavaScript or mobile apps.Request a token
/api/v1/auth/token
Request body
| Parameter | Type | Required | Description |
|---|---|---|---|
| apiKey | string (UUID) | Required | Your API key, provided by MoovLogic. |
| apiSecret | string | Required | Your API secret, provided by MoovLogic. |
curl -X POST https://api.moovlogic.com/api/v1/auth/token \
-H "Content-Type: application/json" \
-d '{
"apiKey": "YOUR_API_KEY",
"apiSecret": "YOUR_API_SECRET"
}'
import requests
response = requests.post(
'https://api.moovlogic.com/api/v1/auth/token',
json={
'apiKey': 'YOUR_API_KEY',
'apiSecret': 'YOUR_API_SECRET'
}
)
response.raise_for_status()
token = response.json()['token']
print(f"Token expires in: {response.json()['expiresIn']} seconds")
<?php
$ch = curl_init('https://api.moovlogic.com/api/v1/auth/token');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'apiKey' => 'YOUR_API_KEY',
'apiSecret' => 'YOUR_API_SECRET'
])
]);
$body = curl_exec($ch);
$data = json_decode($body, true);
$token = $data['token'];
curl_close($ch);
const response = await fetch('https://api.moovlogic.com/api/v1/auth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
apiKey: 'YOUR_API_KEY',
apiSecret: 'YOUR_API_SECRET'
})
});
if (!response.ok) throw new Error(`Auth failed: ${response.status}`);
const { token, expiresIn } = await response.json();
Response — 200 OK
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhcGlfa2V5X2lkIiwiY29tcGFueUlkIjoiMTIzIiwiZXhwIjoxNzE0NjA4MDAwfQ.signature",
"expiresIn": 86400,
"tokenType": "Bearer"
}
{
"error": "invalid_credentials",
"message": "The API key or secret is incorrect.",
"requestId": "req_01HZ9VBKX4E..."
}
Use the token
Include the token in the Authorization header on every subsequent request:
curl https://api.moovlogic.com/api/v1/pricing/service-types \
-H "Authorization: Bearer YOUR_TOKEN"
headers = {'Authorization': f'Bearer {token}'}
response = requests.get(
'https://api.moovlogic.com/api/v1/pricing/service-types',
headers=headers
)
service_types = response.json()['serviceTypes']
<?php
$ch = curl_init('https://api.moovlogic.com/api/v1/pricing/service-types');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer $token"]
]);
$data = json_decode(curl_exec($ch), true);
curl_close($ch);
const response = await fetch('https://api.moovlogic.com/api/v1/pricing/service-types', {
headers: { 'Authorization': `Bearer ${token}` }
});
const { serviceTypes } = await response.json();
Token expiry and caching
Tokens are valid for 24 hours (expiresIn: 86400 seconds).
401. This avoids failed requests at the exact expiry boundary.import time, requests
_token_cache = {'token': None, 'expires_at': 0}
def get_token():
if _token_cache['token'] and time.time() < _token_cache['expires_at']:
return _token_cache['token']
r = requests.post(
'https://api.moovlogic.com/api/v1/auth/token',
json={'apiKey': API_KEY, 'apiSecret': API_SECRET}
)
r.raise_for_status()
data = r.json()
_token_cache['token'] = data['token']
_token_cache['expires_at'] = time.time() + (23 * 3600) # refresh at 23h
return _token_cache['token']
let cachedToken = null;
let tokenExpiresAt = 0;
async function getToken() {
if (cachedToken && Date.now() < tokenExpiresAt) return cachedToken;
const res = await fetch('https://api.moovlogic.com/api/v1/auth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ apiKey: API_KEY, apiSecret: API_SECRET })
});
const { token } = await res.json();
cachedToken = token;
tokenExpiresAt = Date.now() + (23 * 60 * 60 * 1000); // 23 hours
return cachedToken;
}