SDK
El SDK oficial de TypeScript (@fabhub/sdk) se genera y prueba contra el contrato OpenAPI público, por lo que sus métodos nunca divergen de las rutas públicas.
Instalación
npm install @fabhub/sdk
Requiere Node.js 22+.
Autenticación
Construye el cliente con una API key. Un token de acceso emitido por OAuth es en sí mismo una key pk_*, así que pásalo en la misma opción apiKey.
import { FabHubClient } from '@fabhub/sdk';
export const fabhub = new FabHubClient({
apiKey: process.env.FABHUB_API_KEY,
});
Métodos
| Client method | Endpoint | Required scope |
|---|---|---|
getCapabilities | GET /v1 | authenticated |
getAuthContext | GET /v1/auth/context | authenticated |
listItems | GET /v1/items | items:read |
createItem | POST /v1/items | items:write |
getItem | GET /v1/items/{item_id} | items:read |
listItemIngredients | GET /v1/items/{item_id}/ingredients | items:read |
listItemSuppliers | GET /v1/items/{item_id}/suppliers | items:read |
createItemIngredient | POST /v1/items/{item_id}/ingredients | items:write |
updateItemIngredient | PATCH /v1/items/{item_id}/ingredients/{ingredient_id} | items:write |
createItemSupplier | POST /v1/items/{item_id}/suppliers | items:write |
updateItemSupplier | PATCH /v1/items/{item_id}/suppliers/{supplier_id} | items:write |
deleteItemIngredient | DELETE /v1/items/{item_id}/ingredients/{ingredient_id} | items:write |
deleteItemSupplier | DELETE /v1/items/{item_id}/suppliers/{supplier_id} | items:write |
getOrder | GET /v1/orders/{order_id} | orders:read |
listOrderLines | GET /v1/orders/{order_id}/lines | orders:read |
createOrder | POST /v1/orders | orders:write |
updateOrder | PATCH /v1/orders/{order_id} | orders:write |
updateItem | PATCH /v1/items/{item_id} | items:write |
deleteItem | DELETE /v1/items/{item_id} | items:write |
listOrders | GET /v1/orders | orders:read |
listContacts | GET /v1/contacts | contacts:read |
getContact | GET /v1/contacts/{contact_id} | contacts:read |
createContact | POST /v1/contacts | contacts:write |
updateContact | PATCH /v1/contacts/{contact_id} | contacts:write |
deleteContact | DELETE /v1/contacts/{contact_id} | contacts:write |
getOrganization | GET /v1/organization | organization:read |
getUsageSummary | GET /v1/usage | usage:read |
listStockLevels | GET /v1/stock-levels | inventory:read |
listStockDocuments | GET /v1/stock-documents | inventory:read |
getStockDocument | GET /v1/stock-documents/{document_id} | inventory:read |
createStockDocument | POST /v1/stock-documents | inventory:write |
listStockDocumentLines | GET /v1/stock-documents/{document_id}/lines | inventory:read |
createStockDocumentLine | POST /v1/stock-documents/{document_id}/lines | inventory:write |
updateStockDocumentLine | PATCH /v1/stock-documents/{document_id}/lines/{line_id} | inventory:write |
submitStockDocument | POST /v1/stock-documents/{document_id}/submit | inventory:write |
cancelStockDocument | POST /v1/stock-documents/{document_id}/cancel | inventory:write |
approveStockDocument | POST /v1/stock-documents/{document_id}/approve | inventory:write |
deleteStockDocument | DELETE /v1/stock-documents/{document_id} | inventory:write |
deleteStockDocumentLine | DELETE /v1/stock-documents/{document_id}/lines/{line_id} | inventory:write |
updateStockDocument | PATCH /v1/stock-documents/{document_id} | inventory:write |
listWebhooks | GET /v1/webhooks | webhooks:read |
createWebhook | POST /v1/webhooks | webhooks:write |
getWebhook | GET /v1/webhooks/{webhook_id} | webhooks:read |
updateWebhook | PATCH /v1/webhooks/{webhook_id} | webhooks:write |
deleteWebhook | DELETE /v1/webhooks/{webhook_id} | webhooks:delete |
listWebhookDeliveries | GET /v1/webhooks/{webhook_id}/deliveries | webhooks:deliveries:read |
listAuditEvents | GET /v1/audit/events | audit:read |
Paginación
let page = 1;
let totalPages = 1;
do {
const result = await fabhub.listItems({ page, pageSize: 100 });
// handle result.data
totalPages = result.pagination.totalPages;
page += 1;
} while (page <= totalPages);
Escrituras idempotentes
const { data: item } = await fabhub.createItem(
{ name: 'Widget', itemType: 'product' },
{ idempotencyKey: crypto.randomUUID() },
);
Errores tipados
import { FabHubApiError } from '@fabhub/sdk';
try {
await fabhub.getItem('does-not-exist');
} catch (err) {
if (err instanceof FabHubApiError) {
console.error(err.status, err.code, err.message); // e.g. 404 NOT_FOUND ...
}
}
Verificación de la firma de webhook
import { verifyFabHubWebhookSignature } from '@fabhub/sdk';
const result = verifyFabHubWebhookSignature({
signingSecret: process.env.FABHUB_WEBHOOK_SECRET,
rawBody, // the exact raw request body string/bytes, before JSON parsing
timestamp: req.headers['x-fabhub-timestamp'],
signature: req.headers['x-fabhub-signature'],
});
if (!result.ok) {
// reject: result.reason explains why (e.g. 'invalid_signature')
}
Protección frente a la divergencia
El mapeo de operaciones del SDK se comprueba contra OpenAPI en CI, por lo que los métodos públicos del SDK no pueden divergir silenciosamente de las rutas públicas ni apuntar a superficies internas.