Skip to content

Best practices

Conceptual guidance for building a robust integration. For per-endpoint parameters see the API Reference; for pagination see Pagination.

Cache access tokens and reuse them for their lifetime (expires_in) instead of requesting a new token per call:

let cachedToken = null;
let tokenExpiry = null;
async function getToken() {
if (cachedToken && Date.now() < tokenExpiry) {
return cachedToken;
}
const response = await requestToken();
cachedToken = response.access_token;
tokenExpiry = Date.now() + (response.expires_in * 1000);
return cachedToken;
}

Always check the response and surface the API’s error message:

try {
const response = await fetch(url, { headers: { Authorization: `Bearer ${token}` } });
if (!response.ok) {
const error = await response.json();
throw new Error(`API Error: ${error.message}`);
}
return await response.json();
} catch (error) {
console.error('API request failed:', error);
// Implement retry logic for 5xx errors
}

See Pagination for cursor-based (DynamoDB) and offset/syncToken (OpenSearch) strategies and when to use each.

For 429 or 5xx responses, back off exponentially:

async function fetchWithRetry(url, options, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const response = await fetch(url, options);
if (response.status === 429 || response.status >= 500) {
if (attempt === maxRetries - 1) throw new Error('Max retries exceeded');
await sleep(Math.pow(2, attempt) * 1000); // 1s, 2s, 4s
continue;
}
return response;
} catch (error) {
if (attempt === maxRetries - 1) throw error;
await sleep(Math.pow(2, attempt) * 1000);
}
}
}