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 appmakeAxhub 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 }); // writeFor 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 deniedWhen 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);
}
}