Extend
Embed the gateway
Compose the gateway in your own Node process with createGateway, providers and adapters.
createGateway is dependency-injected: you hand it a validated config, a receipt store, payment providers, optional authorization providers and protocol adapters. This is the same composition the gateway's own entry point performs.
Full composition
import {
createAcpAdapter,
createGateway,
loadConfig,
receipts,
type PaymentProvider,
type ProtocolAdapter,
} from '@devlab.group/agent-commerce';
import { mcp } from '@devlab.group/agent-commerce/mcp';
import { x402 } from '@devlab.group/agent-commerce/x402';
import { ap2 } from '@devlab.group/agent-commerce/ap2';
const config = await loadConfig(); // AGENT_COMMERCE_CONFIG or ./config.yaml
const store = receipts({ path: config.storage.receipts.path });
await store.init(); // a store that will not open is fatal
const paymentProviders: PaymentProvider[] = [];
const rail = config.payments.x402;
if (rail?.enabled) {
paymentProviders.push(
x402({
network: rail.network,
rpcUrl: rail.rpcUrl,
asset: rail.asset as `0x${string}`,
assetName: rail.assetName,
assetVersion: rail.assetVersion,
assetDecimals: rail.assetDecimals,
payTo: rail.payTo as `0x${string}`,
maxTimeoutSeconds: rail.maxTimeoutSeconds,
facilitator: rail.facilitator,
...(rail.allowMainnet !== undefined ? { allowMainnet: rail.allowMainnet } : {}),
...(rail.allowUnauthenticatedFacilitator !== undefined
? { allowUnauthenticatedFacilitator: rail.allowUnauthenticatedFacilitator }
: {}),
}),
);
}
const mandates = config.authorization?.ap2;
const authorizationProviders = mandates?.enabled ? [ap2({ config: mandates })] : [];
const protocolAdapters: ProtocolAdapter[] = [];
if (config.protocols.mcp.enabled) {
protocolAdapters.push(mcp({ mountPath: config.protocols.mcp.mountPath }));
}
const acp = config.protocols.acp;
if (acp.enabled) {
protocolAdapters.push(
createAcpAdapter({
mountPath: acp.mountPath,
token: acp.auth.token,
operations: acp.checkout.operations,
idempotency: acp.idempotency,
}),
);
}
const gateway = await createGateway({
config,
store,
paymentProviders,
authorizationProviders,
protocolAdapters,
});
const { url } = await gateway.listen();
process.on('SIGTERM', async () => {
await gateway.close();
for (const provider of authorizationProviders) provider.close();
await store.close();
process.exit(0);
});The A2A adapter is not part of the published entry points; the repository's own entry point wires it from
src/protocols/a2a.GatewayOptions
configGatewayConfigrequiredFrom
loadConfig() or parseConfig(raw, env).storeReceiptStorerequiredreceipts({ path }) — SQLite; ':memory:' for tests. Call init() before use.paymentProvidersPaymentProvider[]requiredEmpty is valid for a gateway serving only free resources.
authorizationProvidersAuthorizationProvider[]Absent means no resource requires authorization.
protocolAdaptersProtocolAdapter[]requiredHTTP routes are built in; add MCP, ACP or your own adapters.
logger / clock / ids / backendInjectable for tests;
backend overrides the HTTP backend executor.GatewayInstance
| Member | Purpose |
|---|---|
listen() | binds server.host:server.port, resolves { url } |
close() | stops the server and adapters |
pipeline | the ExecutionPipeline every adapter calls |
resources | the resource registry |
server | the Fastify instance — use .inject() in tests |