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 wired to the EnfinitOS platform endpoints that exist today. Vendor-side SDK integrations (Broadsign / VIOOH / DJI / Tizen / Alexa / Twilio / Stripe / etc.) land per-customer at pilot integration time — those bring the renderer/transport/exchange-specific code; the EnfinitOS half is ready.

README

The developer-facing documentation in full

The same README the SDK package ships with — rendered here at build time so what you read matches exactly what you install.

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, published alongside the April 2027 platform launch.

Sandbox

Run this SDK against a real tenant

The browser demo at enfinitos.com/sandbox runs today against a shared synthetic tenant. The dedicated developer sandbox — your own persistent tenant, API keys, full HTTP-contract coverage — opens ahead of the April 2027 platform launch.