Call with the SDK

Use @ax-hub/sdk to easily fetch the logged-in user, app data, and external DBs from your app.


When your app needs the AxHub backend — who's logged in, app data, an external DB — fetch it with @ax-hub/sdk. You don't have to wire up paths, auth, and errors yourself.

Template apps already include it. In the Next.js template, just use makeAxhub() and makeApp() from lib/axhub-server.ts.

Getting started

These two lines cover most cases. The template connects you as the logged-in user automatically.

const sdk = await makeAxhub(); // connected as the logged-in user
const app = await makeApp();   // connected to this app

makeAxhub and makeApp are server-only (Server Components, Route Handlers, Server Actions). Don't use them in client (browser) code.

Outside the app (agents, CI, external scripts), you connect with a personal token (PAT) instead. Inside the app, the two lines above are enough.

The logged-in user

You can see who came in.

const me = await sdk.identity.me();
// me.email, me.name, me.tenants (their company and role)

Working with app data

Load a table, then read and write.

const app = await makeApp();
const todos = await app.data.discover('todos'); // figures out the table structure for you
await todos.list({ limit: 20 });                 // read
await todos.insert({ title: 'A task', done: false }); // write

For a quick start, discover('tableName') is enough. To filter, build conditions with where (no raw SQL needed).

import { defineSchema, where, and } from '@ax-hub/sdk';

const Orders = defineSchema({ table: 'orders', columns: { status: 'string', total: 'number' } });

const paid = await app.data.table(Orders).list({
  where: and(where('status').eq('paid'), where('total').gt(100)),
});

Querying external DBs

Query a connected external DB through the gateway. Just give the connector name.

const res = await queryConnector({
  connector: 'my-db',
  path: 'public/employees',
  sql: 'SELECT id, name FROM employees WHERE active = ? LIMIT ?',
  params: [true, 10], // pass values via ? (never inline them into the SQL string)
});
// res.rows holds the results; res.allowed = false means access was denied

When something goes wrong

The SDK tells you what failed via e.code. Branch on code, not the message text (messages can change).

import { AxHubError, ConflictError } from '@ax-hub/sdk';

try {
  await todos.insert({ id: 't1' });
} catch (e) {
  if (e instanceof ConflictError) {
    // handle an existing/duplicate value
  } else if (e instanceof AxHubError) {
    console.error(e.code, e.requestId);
  }
}