fix: try gateway for Transak token refresh before legacy API

Production gateway rejects tokens from api.transak.com. Try getting
the access token from the gateway endpoint first (which staging
confirms works), then fall back to the legacy API endpoint.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jeff Emmett 2026-04-03 03:58:09 +00:00
parent e61da960ea
commit 125bed3ad7
1 changed files with 37 additions and 26 deletions

View File

@ -13,16 +13,18 @@
export type TransakEnv = 'STAGING' | 'PRODUCTION';
const API_URLS = {
STAGING: 'https://api-stg.transak.com',
PRODUCTION: 'https://api.transak.com',
} as const;
// Both token refresh and session creation go through the gateway
const GATEWAY_URLS = {
STAGING: 'https://api-gateway-stg.transak.com',
PRODUCTION: 'https://api-gateway.transak.com',
} as const;
// Fallback: legacy partner API (if gateway token refresh fails)
const API_URLS = {
STAGING: 'https://api-stg.transak.com',
PRODUCTION: 'https://api.transak.com',
} as const;
// Cached access token (valid for 7 days)
let _cachedToken: { token: string; expiresAt: number; env: TransakEnv } | null = null;
@ -76,30 +78,39 @@ async function getAccessToken(): Promise<string> {
const apiSecret = getTransakApiSecret();
if (!apiKey || !apiSecret) throw new Error('Transak API key or secret not configured');
const apiUrl = API_URLS[env];
const res = await fetch(`${apiUrl}/partners/api/v2/refresh-token`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'api-secret': apiSecret,
},
body: JSON.stringify({ apiKey }),
});
const body = JSON.stringify({ apiKey });
const headers = { 'Content-Type': 'application/json', 'api-secret': apiSecret };
if (!res.ok) {
const err = await res.text();
throw new Error(`Transak refresh-token failed: ${res.status} ${err}`);
// Try gateway first (required for production session tokens), then legacy API
const urls = [
`${GATEWAY_URLS[env]}/partners/api/v2/refresh-token`,
`${API_URLS[env]}/partners/api/v2/refresh-token`,
];
let lastError = '';
for (const url of urls) {
try {
const res = await fetch(url, { method: 'POST', headers, body });
if (!res.ok) {
lastError = `${url}: ${res.status} ${await res.text()}`;
console.warn(`[transak] Token refresh failed at ${url}: ${res.status}`);
continue;
}
const data = await res.json() as { data: { accessToken: string; expiresAt: number } };
_cachedToken = {
token: data.data.accessToken,
expiresAt: data.data.expiresAt,
env,
};
console.log(`[transak] Access token refreshed from ${url} (env=${env}, expires=${new Date(data.data.expiresAt * 1000).toISOString()})`);
return _cachedToken.token;
} catch (err) {
lastError = `${url}: ${err}`;
console.warn(`[transak] Token refresh error at ${url}:`, err);
}
}
const data = await res.json() as { data: { accessToken: string; expiresAt: number } };
_cachedToken = {
token: data.data.accessToken,
expiresAt: data.data.expiresAt,
env,
};
console.log(`[transak] Access token refreshed (env=${env}, expires=${new Date(data.data.expiresAt * 1000).toISOString()})`);
return _cachedToken.token;
throw new Error(`Transak refresh-token failed on all endpoints: ${lastError}`);
}
/**