EnfinitOSEnfinitOS
DevelopersOperator & brand
Production-ready scaffold

Brand SDK — Ruby

Ruby gem — same shape as the TypeScript / Python clients, idiomatic for the Rails crowd.

enfinitos_brandSubstrate ALLRuby
Install

Get the SDK

gem install enfinitos_brand

About this status badge

Typed, tested, documented, and grounded in the 2026 platform reality. Awaiting first customer-integration validation.

README

The developer-facing documentation in full

Rendered from packages/sdks/brand-rb/README.md at build time — the same source the package ships with.

EnfinitOS Brand SDK — Ruby

enfinitos_brand — the read-only Ruby gem a brand (advertiser) uses to query its own delivery proof, metering, and settlement records directly from the EnfinitOS platform, without going through the operator's reporting plane.

Mirrors @enfinitos/sdk-brand (TypeScript), enfinitos_brand (Python), enfinitos-brand-go (Go), and com.enfinitos:sdk-brand (Java) one-for-one. When one moves, this gem moves with it.

Who should use it

A brand engineering team that wants to:

  • pull a Merkle-rooted signed proof of every billable delivery and verify it against the Auditor gem;
  • reconcile its own attribution numbers against the platform's metered usage before paying the invoice;
  • iterate settlement invoices and lines for finance/AP;
  • open a dispute (with signed counter-evidence) when its own auditor disagrees with what was billed.

The SDK is scoped read-only to campaigns the calling brand owns. The single write operation — disputes.open — is idempotent and bound to the brand's auditor key.

Authentication

Every request carries:

  • Authorization: Bearer <brand_api_key> — issued by the platform to a single brand tenant; rotatable; read-only on owned campaigns plus dispute-open;
  • X-Enfinitos-Brand: <brand_id> — the brand's tenant id; allows the platform WAF to rate-limit per-tenant before auth decode.

The platform rejects any mismatch between the key's owner and the header.

Installation

This gem is currently distributed inside the EnfinitOS monorepo. Add to your Gemfile:

gem "enfinitos_brand", "~> 0.0.1", path: "vendor/enfinitos_brand"

Requires Ruby 3.2+. Zero third-party runtime dependencies.

Getting started

require "enfinitos_brand"

client = EnfinitOS::Brand::Client.new(
  api_base_url: "https://api.enfinitos.com",
  brand_id:     "brand_acme_co",
  api_key:      ENV.fetch("ENFINITOS_BRAND_API_KEY")
)

# 1. List my campaigns.
page = client.campaigns.list
page.items.each do |c|
  puts "#{c.campaign_id} [#{c.status}] billed=#{c.total_billed_minor}"
end

# 2. Fetch a signed proof pack for one campaign.
pack = client.proof.pack(page.items.first.campaign_id)

# 3. Verify against the Auditor gem (separate gem —
#    enfinitos_auditor — performs Merkle + signature verification
#    offline, with no network round-trip).
#
#    EnfinitOS::Auditor::Client.new(...).verify_pack(pack)

Module reference

client.campaigns

  • list(status:, cursor:, limit:) — cursor-paginated list of owned campaigns. All keyword args optional.
  • get(campaign_id) — single campaign.

client.proof

  • summary(campaign_id) — cheap Merkle-root rollup (merkle_root, record_count, signer info).
  • pack(campaign_id) — full signed SignedProofPack; pass to the Auditor gem for offline verification.
  • chain(campaign_id, cursor:, limit:) — cursor-paginated per-leaf records.

For verification use pack — the chain endpoint is for inspection and incremental reconciliation only.

client.metering

  • summary(campaign_id) — per-unit totals.
  • breakdown(campaign_id, unit:) — per-day, per-substrate rollup of a single billable unit ("impressions", "plays", "seconds", "meters", "interactions", "verified_views").

client.settlement

  • invoices(from:, to:) — invoices issued to the brand; optional inclusive (from, to) window on issued_at. Accepts Time or ISO-8601 strings.
  • invoice(invoice_id) — single invoice with lines.
  • line(line_id) — single invoice line; carries the proof_slice_root that pins it to the corresponding Merkle subtree.

client.disputes

  • open(campaign_id:, reason:, evidence:, idempotency_key:) — open a dispute. The gem auto-generates a UUID v4 idempotency key when one isn't supplied; cron re-runs are safe.
  • list(status:) — list the brand's disputes.
  • get(dispute_id) — single dispute.

The dispute body's free-form reason is informational; the operator's response is bound to the SignedEvidence only.

Error model

The gem raises three exception families, all under EnfinitOS::Brand:

  • APIError — the platform answered with a non-2xx status or a 2xx envelope carrying ok: false. Carries code, http_status, correlation_id, details, plus the helpers client_error? and retryable?.
  • TransportError — connection-level failure (DNS, timeout, TLS, refused).
  • Error — base class; rarely raised directly.

Typical pattern:

begin
  client.campaigns.get(id)
rescue EnfinitOS::Brand::APIError => e
  if e.retryable?
    # 408 / 429 / 5xx — defer to your worker's backoff.
  elsif e.code == "CAMPAIGN_NOT_FOUND"
    # tenant-bound 404 — the campaign either doesn't exist
    # or isn't owned by this brand. The platform deliberately
    # does NOT distinguish the two.
  else
    raise
  end
end

The SDK does not retry by default. Brand-side systems sit downstream of the brand's own retry middleware (Sidekiq, Faktory, shoryuken, ...); doubling them up has caused duplicate-dispute filings in the past. Opt in by checking retryable? and re-issuing yourself.

Cross-reference

  • Auditor gem (enfinitos_auditor) — offline verification of signed proof packs returned by proof.pack. Pure crypto; no network.
  • Operator Reporting — the platform's operator-facing report surface answers the same questions from the operator's point of view; brands deliberately do NOT consume it directly.
  • REST contractapps/api is the source of truth; the SDK pins shapes via Data.define types and is regenerated when contracts move.

Wire conventions

Every request also includes:

  • X-Enfinitos-Sdk: brand-rb
  • X-Enfinitos-Sdk-Version: 0.0.1
  • X-Enfinitos-Contract: 1
  • User-Agent: enfinitos-sdk-brand-rb/0.0.1 [(tag)]
  • Idempotency-Key: <uuid> on POST /v1/brand/disputes (auto-generated by the SDK when the caller omits one).

The platform's response envelope is:

{ "ok": true, "data": { ... }, "contractVersion": 1 }

or

{ "ok": false, "error": { "code": "...", "message": "...", "correlationId": "..." } }

The SDK unwraps both and surfaces only data or the typed APIError. The X-Contract-Version response header is captured on errors for drift-monitoring tooling.

Tests

bundle exec rspec

Tests use the injectable :transport keyword on Client.new; no real HTTP server is required.

API reference

Hit the HTTP surface directly

The Brand SDK — Ruby is a thin client over the same governed HTTP API every other SDK calls. The full OpenAPI 3.1 reference lives on the docs site.

Sandbox

Run this SDK against a real tenant

The hosted sandbox is the fastest way to verify Brand SDK — Ruby against a real EnfinitOS tenant before committing to a pilot. Launching Q4 2026.