Getting started
From zero to your first classified email in about ten minutes.
This walks you from a fresh account to reading a real, classified message through the gateway. You'll register an app, connect a mailbox, and make your first authenticated call.
What you need
A Thread developer account and Node 18+. Everything
below uses the official SDK, @jointhread/sdk.
Register an app
In the developer console, choose Register app. You'll get four credentials — copy them somewhere safe, because the secrets are shown only once:
| Credential | Used for | Visibility |
|---|---|---|
clientId | Identifies your app in the Connect flow | Public |
clientSecret | Exchanging connect codes (server-side) | Secret — shown once |
apiKey | Calling the gateway data plane | Secret — shown once |
webhookSecret | Verifying webhook signatures | Secret — shown once |
You can rotate any secret later from the app's detail page.
Install the SDK
npm install @jointhread/sdkAdd a Connect button
Your user authorizes a scoped grant on Thread's hosted consent page. From the browser:
import { openThreadConnect } from '@jointhread/sdk';
button.onclick = () =>
openThreadConnect({
baseUrl: 'https://app.jointhread.com', // Thread's hosted consent
clientId: process.env.THREAD_CLIENT_ID!, // from the console
redirectUri: 'https://yourapp.com/thread/callback',
scopes: ['financial'], // seeds the user's default filter
state: csrfToken,
});Thread redirects the user back to your redirectUri?code=...&state=....
Exchange the code (server)
On your callback route, swap the one-time code for a stable accountId. This call uses
your client secret, so it must run on your server.
import { exchangeConnectCode } from '@jointhread/sdk';
const { accountId, mailbox, scopes } = await exchangeConnectCode({
baseUrl: 'https://api.jointhread.com',
clientId: process.env.THREAD_CLIENT_ID!,
clientSecret: process.env.THREAD_CLIENT_SECRET!,
code: req.query.code,
});
// Store accountId against your user — it's how Thread addresses this mailbox.Read message metadata
Use your API key with the ThreadClient. Address the mailbox by the accountId you
just stored, and (in this phase) narrow by sender domain:
import { ThreadClient } from '@jointhread/sdk';
const thread = new ThreadClient({
apiKey: process.env.THREAD_API_KEY!,
baseUrl: 'https://gw.jointhread.com',
});
const { messages } = await thread.messages.list({
accountId,
fromDomain: 'amazon.com',
});
console.log(messages[0]?.subject, messages[0]?.labels);You get back metadata and Thread's classification labels — never the raw body.