@vultur-ar/sdk
v0.1.0
Published
Official TypeScript SDK for the Vultur API — a hosted runtime that lets your AI agent emit AFIP-CAE-backed facturas, calculate IIBB retention, and audit-log every operation in Argentina. Wraps /api/v1 with typed clients + a webhook signature verifier.
Maintainers
Readme
@vultur-ar/sdk
Official TypeScript SDK for Vultur — a hosted runtime that lets your AI agent issue AFIP-CAE-backed facturas, calculate IIBB retention, and audit-log every operation in Argentina.
Zero deps. Works in Node 18+, Bun, Deno, Cloudflare Workers, Vercel Edge, browsers.
Install
npm i @vultur-ar/sdkUsage
import { Vultur } from "@vultur-ar/sdk";
const vultur = new Vultur({
apiKey: process.env.VULTUR_API_KEY!, // vk_live_… or vk_test_…
});
const factura = await vultur.facturas.create({
sociedad: "acme-ai",
total: 121_000, // ARS centavos
cliente: "20-12345678-9",
concepto: "Servicios — agente IA",
});
console.log(factura.cae); // → "70123456789012"Idempotency
Pass an idempotencyKey on create to make retries safe. Vultur returns the original response if it has seen the key in the last 24h.
import { randomUUID } from "node:crypto";
await vultur.facturas.create({
sociedad: "acme-ai",
total: 121_000,
idempotencyKey: randomUUID(),
});Typed error handling
import {
Vultur,
VulturAfipRejection,
VulturRateLimitError,
VulturAuthError,
} from "@vultur-ar/sdk";
try {
await vultur.facturas.create({ /* ... */ });
} catch (err) {
if (err instanceof VulturAuthError) {
// Rotate or check the API key.
} else if (err instanceof VulturRateLimitError) {
await sleep(err.resetSeconds * 1000);
// retry
} else if (err instanceof VulturAfipRejection) {
// AFIP rejected the comprobante — log err.message + err.details
// and surface to the operator.
} else {
throw err;
}
}Auto-retry
The SDK ships off-by-default retry behavior so it doesn't conflict with your own queue:
const vultur = new Vultur({
apiKey: "...",
retryOn429: true, // one retry honoring X-RateLimit-Reset
maxRetries: 3, // exponential backoff on 5xx, up to N tries
});List + paginate
let cursor: string | null = null;
do {
const page = await vultur.facturas.list({
limit: 100,
starting_after: cursor ?? undefined,
status: "authorized",
});
for (const f of page.data) console.log(f.numero, f.total);
cursor = page.next_cursor;
} while (cursor);Verify a webhook
Vultur signs every outbound webhook delivery (HMAC-SHA256 over <ts>.<body> in Stripe's header shape).
import { verifyWebhookSignature } from "@vultur-ar/sdk";
export async function POST(req: Request) {
const rawBody = await req.text();
const ok = await verifyWebhookSignature({
rawBody,
signatureHeader: req.headers.get("x-vultur-signature"),
secret: process.env.VULTUR_WEBHOOK_SECRET!,
});
if (!ok) return new Response("invalid signature", { status: 400 });
// ... process event ...
}Endpoints
| Method | Path | SDK |
|---|---|---|
| POST | /api/v1/facturas | vultur.facturas.create(args) |
| GET | /api/v1/facturas/:id | vultur.facturas.retrieve(id) |
| GET | /api/v1/facturas | vultur.facturas.list(opts) |
| GET | /api/v1/societies/:slug | vultur.societies.retrieve(slug) |
| GET | /api/v1/usage | vultur.usage.retrieve() |
| GET | /api/v1/health | vultur.health.check() |
Full reference at https://vultur.ar/docs.
License
MIT — Nazareno Clemente
