Thrixel API

Sign in with Thrixel

Let your users connect their Thrixel account to your app in three steps.

Add a "Sign in with Thrixel" button to your app. Your user approves once in a browser, you get their API key, and you call the API as them. They never see or paste a key.

Three requests. No app registration, no client secret, nothing to wait for.

1. Ask for a code

Call this from your server when the user clicks your button.

POST /cli/device/start
curl -X POST https://api.thrixel.com/api/v1/cli/device/start \
  -H "Content-Type: application/json" \
  -d '{
    "client_name": "Your App Name"
  }'
{
  "device_code": "kL9x...",
  "user_code": "WXYZ-4821",
  "verification_uri_complete": "https://thrixel.com/create/cli-auth?code=WXYZ-4821",
  "expires_in": 600,
  "interval": 5
}

2. Send the user to approve

Open verification_uri_complete in a popup or new tab, and show them user_code so they can check it matches.

They sign in, confirm, approve. If they have no Thrixel account yet, they can sign up on that same page.

Keep device_code on your server. It is the secret that collects the key.

3. Poll for the key

Every interval seconds, until it returns the key.

POST /cli/device/poll
curl -X POST https://api.thrixel.com/api/v1/cli/device/poll \
  -H "Content-Type: application/json" \
  -d '{
    "device_code": "kL9x..."
  }'
{
  "api_key": "sk-thrixel-...",
  "key_id": "8f3c1a2b-...",
  "email": "user@example.com"
}

Store api_key against that user. Show them email so they know which account they connected. Done.

While you wait, poll returns 400 with one of these in detail.error:

ErrorWhat to do
authorization_pendingNot approved yet. Keep polling.
slow_downYou polled too fast. Wait longer, then continue.
access_deniedThey declined. Stop.
expired_tokenExpired or already collected. Start again at step 1.

Complete example

// Server side. Returns the user's API key, or throws.
async function connectThrixel() {
  const API = "https://api.thrixel.com/api/v1/cli/device";
 
  const auth = await (
    await fetch(`${API}/start`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ client_name: "Your App Name" }),
    })
  ).json();
 
  // Show auth.user_code, and open auth.verification_uri_complete for the user.
 
  const deadline = Date.now() + auth.expires_in * 1000;
  let wait = auth.interval * 1000;
 
  while (Date.now() < deadline) {
    await new Promise((r) => setTimeout(r, wait));
 
    const res = await fetch(`${API}/poll`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ device_code: auth.device_code }),
    });
 
    if (res.ok) return await res.json(); // { api_key, key_id, email }
 
    const { error } = (await res.json()).detail;
    if (error === "authorization_pending") continue;
    if (error === "slow_down") { wait += 5000; continue; }
    throw new Error(error);
  }
  throw new Error("expired_token");
}

Keep the key on your server

It has full access to that user's account, including their cubes. Never put it in the browser or in a URL.

Before you ship

  • Codes expire in 10 minutes. If nobody approves in time, start over.
  • The key is delivered once. Store it on the first successful poll.
  • Jobs bill to the user, on their plan and their limits. Not yours.
  • On a 401, run the flow again. The user can revoke your key from their account, and reconnecting your app replaces the key you were holding.
  • Set client_name to your app's name. Your user sees it on the approval screen and in their account afterwards.

On this page