ridebuilder-affiliate (Ruby)
Server-side SDK for RideBuilder's FirstParty affiliate program. It does two things:
- Capture the
click_ida shopper arrives with, so your backend can bind it to the cart/order. - Report checkout and return postbacks to RideBuilder (auth, retries, idempotency handled).
Mirrors the Node/.NET/Python/PHP/Java SDKs — same contract, verified by the shared conformance suite.
Install
gem install ridebuilder-affiliate
or in a Gemfile: gem "ridebuilder-affiliate". Requires Ruby 3.0+. No runtime dependencies — the
default transport uses the stdlib net/http.
The pattern: capture at landing, bind to the order
require "ridebuilder/affiliate"
# 1. On landing, read a validated click_id off the request URL and persist it onto YOUR cart record.
click_id = RideBuilder::Affiliate::Capture.from_url(request.fullpath)
cart.ridebuilder_click_id = click_id if click_id
# 2. At order time, send the postback from your backend.
rb = RideBuilder::Affiliate::Client.new(api_key: ENV.fetch("RIDEBUILDER_API_KEY"))
rb.report_checkout(
order_id: order.id,
subtotal: "199.99", # major units; a string keeps it exact
currency: "USD",
click_id: order.ridebuilder_click_id
)
Store the API key server-side (env/secrets) — never in frontend code.
Decoupled frontend (e.g. React) + separate Ruby backend
The browser snippet captures the click_id into a first-party cookie; get it to your backend one of two ways:
# Same registrable domain — the cookie rides along; read it off the Cookie header:
click_id = RideBuilder::Affiliate::Capture.(request.get_header("HTTP_COOKIE"))
# Cross-domain / mobile — the frontend forwards it in the checkout call:
click_id = RideBuilder::Affiliate::Capture.from_headers(request.headers) # default: X-RideBuilder-Click-Id
Either way, report_checkout is unchanged — that's the SDK's real value in a decoupled setup.
Refunds
rb.report_return(return_id: refund.id, order_id: order.id, refund_amount: "49.95", currency: "USD")
Integration protocol (register / verify / heartbeat)
rb = RideBuilder::Affiliate::Client.new(api_key: api_key, environment: "production") # or "sandbox"
reg = rb.register # handshake on install/startup; returns a stable integration id
rb.verify # deploy/CI self-test — raises RideBuilder::Affiliate::Error on a bad/rotated key
rb.heartbeat # periodic liveness (call on a schedule)
The SDK reports its own type (ruby_sdk), version, and default capabilities.
Capture helpers
All validate ref == "ridebuilder" and the UUID-v4 click_id, returning nil otherwise:
Capture.from_url(url)— from an absolute or relative URL.Capture.from_query(hash)— from a decoded query map.Capture.from_cookie_header(cookie_header)— recover it from theridebuilder_attributioncookie.Capture.from_headers(headers, name = "X-RideBuilder-Click-Id")— from a forwarding header (decoupled path).
Client options
RideBuilder::Affiliate::Client.new(
api_key:, # required
base_url: nil, # defaults to https://api.ridebuilder.com/v1
max_retries: 3, # retries on network errors, timeouts, 5xx, 429
timeout_ms: 10_000, # per-attempt timeout
environment: "production",
transport: nil # inject an object responding to #call(method, url, headers, body)
)
report_checkout / report_return return PostbackResult (.accepted, .status; 202 = accepted,
validated asynchronously). Invalid input raises a non-retryable RideBuilder::Affiliate::Error; auth/size
failures (401, 413) raise with .status and .error_code. Amounts must be > 0 with at most 2 decimal
places (pass a string to avoid float rounding) or the call raises up front.
Tests
Plain Ruby, no test framework required:
ruby test/conformance.rb # the shared cross-language fixtures
ruby test/unit.rb # validation, capture, money, retry/error, identity
Contract
Wraps the RideBuilder affiliate REST contract — POST /v1/postback/checkout, /postback/return,
/postback/health, the /integration/* endpoints, the /redirect link format, and API-key provisioning.
Verified byte-for-byte against the Node/.NET/Python/PHP/Java SDKs by the shared conformance fixtures.