@enfinitos/sdk-brand
EnfinitOS Brand/Advertiser SDK — a lightweight REST client that lets a brand (advertiser) query its own delivery proof, metering, and settlement records directly, without going through the operator's reporting plane. Read-only by design and scoped to campaigns the brand owns.
This SDK is intentionally narrow. It is not a buying tool, a creative-management tool, or a planning tool. It exists for one purpose: let the brand independently verify that the campaigns it paid for actually ran the way they were billed, using the platform's cryptographic evidence. Use it to power CFO/finance dashboards, auditor-driven dispute pipelines, and outbound regulatory filings.
Who should use this
You are a brand (advertiser) and:
- you receive invoices from EnfinitOS-connected operators for campaigns you funded;
- you want to reconcile those invoices against your own impression logs, your own auditor's analysis, or a regulator-mandated proof archive;
- you need to file disputes backed by signed counter-evidence the operator is contractually bound to respond to.
If you are an operator, you want the operator-web SDK instead. If you are an auditor verifying signatures, you want @enfinitos/sdk-auditor for the cryptographic primitives. The brand SDK pulls the data; the auditor SDK verifies it.
Authentication
The SDK authenticates with a brand API key, distinct from operator keys and user session tokens:
Authorization: Bearer brk_…
X-Enfinitos-Brand: brand_acme
Brand API keys are issued by EnfinitOS to the brand's tenant admin via the brand portal (see https://brand.enfinitos.com/keys). They are scoped read-only to records the brand owns — campaigns it funded, invoices issued to it. Disputes are the only write surface, and they are bound to the brand's own auditor-key signature, not the API key.
Key rotation is supported: the brand portal issues a new key, the old key stays valid for 24 hours, then is automatically revoked.
Installation
pnpm add @enfinitos/sdk-brand
No third-party HTTP dependencies. Requires Node 20+ (for native fetch).
Getting started
import {
EnfinitOSBrandClient,
EnfinitOSAPIError,
} from "@enfinitos/sdk-brand";
const client = new EnfinitOSBrandClient({
apiBaseUrl: "https://api.enfinitos.com",
brandId: process.env.ENFINITOS_BRAND_ID!,
apiKey: process.env.ENFINITOS_BRAND_API_KEY!,
});
// 1. List active campaigns.
const page = await client.campaigns.list({ status: "ACTIVE" });
console.log(`Brand has ${page.items.length} active campaigns`);
// 2. For each, pull the signed proof pack + invoice line.
for (const cmp of page.items) {
const [pack, summary] = await Promise.all([
client.proof.pack(cmp.campaignId),
client.metering.summary(cmp.campaignId),
]);
// 3. Hand the pack to the Auditor SDK for signature verification.
// (See @enfinitos/sdk-auditor for the verification primitives.)
//
// import { verifyPack } from "@enfinitos/sdk-auditor";
// const verdict = await verifyPack(pack);
// if (!verdict.ok) console.error("DISPUTE:", verdict.reason);
console.log(cmp.name, summary.totals);
}
// 4. On any 4xx/5xx, the SDK throws a typed error.
try {
await client.campaigns.get("does-not-exist");
} catch (e) {
if (e instanceof EnfinitOSAPIError) {
console.error("API error", e.code, e.correlationId);
} else {
throw e;
}
}
Module reference
| Namespace | Methods | Purpose |
|---|---|---|
client.campaigns | list, get | Brand-owned campaigns. Read-only. |
client.proof | summary, pack, chain | Signed evidence (Merkle-rooted per-render ledger). Verify with the Auditor SDK. |
client.metering | summary, breakdown | Billable-unit rollups per campaign. |
client.settlement | invoices, invoice, line | Invoices issued to the brand, with per-line proof-slice roots. |
client.disputes | open, list, get | Brand-raised disputes, backed by signed evidence. The SDK's only write surface. |
See src/types.ts for the full set of typed contracts.
Error model
All non-2xx responses surface as EnfinitOSAPIError:
class EnfinitOSAPIError extends Error {
code: string; // "UNAUTHORIZED", "CAMPAIGN_NOT_FOUND", …
httpStatus: number; // 401, 404, …
correlationId: string; // bind to platform logs
details?: Record<string, unknown>;
isClientError(): boolean;
isRetryable(): boolean;
}
Connection-level failures (DNS, reset, timeout) surface as EnfinitOSTransportError — those never reached the platform and are always safe to retry.
The SDK does not retry automatically. Brand-side systems typically sit behind their own retry middleware (Sidekiq, Faktory, JVM scheduler); a second layer of retries causes phantom-duplicate dispute filings. Opt in via EnfinitOSAPIError.isRetryable().
Cross-reference: Auditor SDK
The brand SDK returns evidence; the Auditor SDK verifies it. The two are deliberately separate packages so you can ship the verifier into an air-gapped environment (a regulator's lab, an internal compliance service) without also pulling in the HTTP client.
| Brand SDK output | Auditor SDK function |
|---|---|
SignedProofPack | verifyPack(pack) |
ProofRecord + Merkle path | verifyLeafInclusion(record, path, root) |
InvoiceLine.proofSliceRoot | verifySlice(slice, root) |
SignedEvidence (dispute) | verifyEvidence(evidence, publicKey) |
See @enfinitos/sdk-auditor for full reference.
Versioning
The SDK pins a wire-protocol contract version (CONTRACT_VERSION). The platform echoes its own version in X-Contract-Version on every response; a brand-side monitoring system that wants to detect drift should compare the two. Minor additions (new optional fields, new metering units) do not bump the contract; non-additive changes do.
Status
Initial release. The brand SDK is API-stable; the underlying platform contracts are at contract version 1.