Better I18NBetter I18N

Installation Tokens

Mint short-lived bi_oat_ tokens for scoped API access.

The access token from the authorization flow cannot read resources directly. To call partner API endpoints, exchange it for a 1-hour installation token:

Mint a token

curl -X POST \
  https://api.better-i18n.com/api/oauth-client/installations/<grant_id>/tokens \
  -H "Authorization: Bearer <access_token>"

Response

{
  "installation_token": "bi_oat_d7ab12...",
  "token_type": "Bearer",
  "expires_at": "2026-04-30T12:00:00.000Z",
  "expires_in": 3600,
  "organization_id": "org_...",
  "project_ids": [],
  "scopes": ["org:read", "keys:read", "keys:write", "translations:write"]
}

project_ids: [] means all projects in this organization. A non-empty array restricts access to those specific projects.

Caching strategy

Mint a new token only when the cached one is within ~60 seconds of expiring:

lib/better-i18n.ts
let cache: { token: string; expiresAt: number } | null = null;

async function getInstallationToken(
  grantId: string,
  accessToken: string,
): Promise<string> {
  if (cache && cache.expiresAt - Date.now() > 60_000) {
    return cache.token;
  }

  const res = await fetch(
    `https://api.better-i18n.com/api/oauth-client/installations/${grantId}/tokens`,
    {
      method: "POST",
      headers: { Authorization: `Bearer ${accessToken}` },
    },
  );
  const data = await res.json();
  cache = {
    token: data.installation_token,
    expiresAt: new Date(data.expires_at).getTime(),
  };
  return cache.token;
}

Do not mint per request. Every mint is logged in the audit trail and rate-limited. In practice you need 1-2 mints per hour.

What's inside the token

The installation token is a Better i18n API key (apikey table row) with embedded permissions:

{
  "type": "installation",
  "grantId": "grt_...",
  "organizationId": "org_...",
  "projectIds": [],
  "scopes": ["keys:read", "keys:write"]
}

The middleware reads these permissions on every request — no additional lookup needed.

Next step

Use the installation token to call resource APIs.

On this page