sdk
The SDK docs should be read as integration setup, not as a loose API dump. Start with the Express middleware if you are integrating a provider endpoint. Reach for HalotClientonly when you are building requester-side automation or a custom client flow.
Installation
Middleware
halot() is the exported provider integration path. It handles quote challenges, receipt verification, and result reporting against the facilitator endpoints. A production route needs a registered serviceIdand provider-signed report headers.
That serviceId must already exist on Halot. The real order is: register the provider, register the service under that provider, then use the returned service ID in middleware.
import { Wallet } from 'ethers';
import { createActorAuthHeaders, halot, nowIso } from '@halot/sdk';
import express from 'express';
const app = express();
app.use(express.json());
const providerId = process.env.HALOT_PROVIDER_ID!;
const providerWallet = new Wallet(process.env.HALOT_PROVIDER_PRIVATE_KEY!);
app.post('/jobs', halot({
serviceId: 'svc_research',
providerHeaders: async (_req, context) => {
if (context.providerId !== providerId) {
throw new Error('Provider assignment mismatch');
}
return createActorAuthHeaders(providerWallet, {
actorId: providerId,
role: 'provider',
method: 'POST',
path: '/facilitator/report',
timestamp: nowIso(),
});
},
}), (req, res) => {
const { jobId, providerId: assignedProviderId, requesterAddress } = req.halot;
const text = runProviderLogic(req.body, { jobId, providerId: assignedProviderId, requesterAddress });
res.json({ text, model: 'gpt-5.4' });
});
HALOT_PROVIDER_IDis the provider ID returned by provider registration. HALOT_PROVIDER_PRIVATE_KEYis the private key for that provider actor authority. You can load those values from a secret manager or the CLI-generated authority file instead of env; the important part is that /facilitator/reportis signed by the same provider actor that owns the registered service.
The middleware uses the hosted Halot target by default. For a local Halot server, pass target: 'local'.
If one route can serve multiple registered services, pass a resolver instead of a fixed string. That keeps the canonical Halot service identity while still letting the provider branch on request data.
app.post('/generate', halot({
serviceId: (req) => {
switch (req.body.model) {
case 'gpt-5.4':
return 'svc_text_gpt54';
case 'gpt-5.4-mini':
return 'svc_text_gpt54mini';
case 'gpt-5.4-nano':
return 'svc_text_gpt54nano';
default:
throw new Error('Unsupported model');
}
},
providerHeaders: async (_req, context) => {
if (context.providerId !== providerId) {
throw new Error('Provider assignment mismatch');
}
return createActorAuthHeaders(providerWallet, {
actorId: providerId,
role: 'provider',
method: 'POST',
path: '/facilitator/report',
timestamp: nowIso(),
});
},
}), async (req, res) => {
const text = await runProviderLogic(req.body);
res.json({ text, model: req.body.model });
});
Requester Client
HalotClientis the optional requester-side helper. It automates the requester flow: trigger a 402 challenge, sign the payment requirement, prepare the job, fund the prepared job through your adapter, confirm the funding transaction, then retry the target endpoint with x-halot-receipt.
import { HalotClient } from '@halot/sdk';
import { Wallet } from 'ethers';
const wallet = new Wallet(process.env.HALOT_PRIVATE_KEY!);
const client = new HalotClient({
wallet: {
address: wallet.address,
signMessage: (message) => wallet.signMessage(message),
},
funding: {
async fund(preparedJob) {
const transactionHash = await fundPreparedJobOnChain(preparedJob);
return { transactionHash };
},
},
defaultNetwork: '0g:mainnet',
});
const response = await client.request('https://provider.example/jobs', {
method: 'POST',
body: { query: 'halot' },
});
Auth & Payment Helpers
The SDK also exports helpers for actor-signed provider or verifier requests and for x402 requirement encoding and signing.
import {
createActorAuthHeaders,
decodePaymentRequirement,
encodePaymentRequirement,
signPaymentRequirement,
} from '@halot/sdk';
Types & Schemas
Shared types such as Quote, PreparedJob, Job, and the Zod schemas behind them are exported for runtime validation and custom integrations.
import {
JobSchema,
PaymentAuthorizationSchema,
PaymentRequirementSchema,
QuoteSchema,
} from '@halot/sdk';
Note: AggregatorClientis an internal helper used by the middleware. The public SDK exports are halot, HalotClient, auth helpers, payment helpers, and shared types. Provider routes may also pass a request-based serviceId resolver when one endpoint fronts multiple registered services.