ridebuilder/affiliate

Server-side SDK for RideBuilder FirstParty affiliate tracking: capture click_id and send checkout/return postbacks.

Maintainers

Package info

github.com/RideBuilder/affiliate-php

Homepage

pkg:composer/ridebuilder/affiliate

Transparency log

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.1.1 2026-08-04 10:14 UTC

This package is auto-updated.

Last update: 2026-08-04 13:14:19 UTC


README

Server-side SDK for RideBuilder's FirstParty affiliate program. It does two things:

  1. Capture the click_id a shopper arrives with, so your backend can bind it to the cart/order.
  2. Report checkout and return postbacks to RideBuilder (auth, retries, idempotency handled).

Mirrors the Node/.NET/Python SDKs — same contract, verified by the shared conformance suite.

Install

composer require ridebuilder/affiliate

Requires PHP 8.1+ and ext-curl (bundled with virtually every PHP). No third-party runtime dependencies — the default transport uses cURL. To run from source without Composer, require 'sdk/php/autoload.php'.

The pattern: capture at landing, bind to the order

Capture the click_id on landing, store it with the cart, and send it at purchase.

use RideBuilder\Affiliate\{RideBuilderClient, Capture, CheckoutInput};

// 1. On landing, read a validated click_id off the request URL and persist it onto YOUR cart record.
$clickId = Capture::fromUrl($_SERVER['REQUEST_URI']);
if ($clickId !== null) {
    $cart->ridebuilderClickId = $clickId;
}

// 2. At order time, send the postback from your backend.
$rb = new RideBuilderClient(apiKey: getenv('RIDEBUILDER_API_KEY'));
$rb->reportCheckout(new CheckoutInput(
    orderId: $order->id,
    subtotal: '199.99',   // major units; string keeps it exact
    currency: 'USD',
    clickId: $order->ridebuilderClickId,
));

Store the API key server-side (env/secrets) — never in frontend code.

Decoupled frontend (e.g. React) + separate PHP backend

If the frontend is separate, the browser snippet captures the click_id into a first-party cookie, and you get it to your backend one of two ways:

// Same registrable domain — the cookie rides along; read it off the Cookie header:
$clickId = Capture::fromCookieHeader($_SERVER['HTTP_COOKIE'] ?? null);

// Cross-domain / mobile — the frontend forwards it in the checkout call:
$clickId = Capture::fromHeaders(getallheaders());   // default header: X-RideBuilder-Click-Id

Either way, reportCheckout is unchanged — that's the SDK's real value in a decoupled setup.

Refunds

$rb->reportReturn(new ReturnInput(
    returnId: $refund->id, orderId: $order->id, refundAmount: '49.95', currency: 'USD',
));

Integration protocol (register / verify / heartbeat)

$rb = new RideBuilderClient(apiKey: $apiKey, environment: 'production'); // or 'sandbox'

$reg = $rb->register();   // handshake on install/startup; returns a stable integration id
$rb->verify();            // deploy/CI self-test — throws RideBuilderException on a bad/rotated key
$rb->heartbeat();         // periodic liveness (call from cron; PHP has no persistent process)

The SDK reports its own type (php_sdk), version, and default capabilities.

Capture helpers

All validate ref == "ridebuilder" and the UUID-v4 click_id, returning null otherwise:

  • Capture::fromUrl($url) — from an absolute or relative URL.
  • Capture::fromQuery($query) — from a decoded query map.
  • Capture::fromCookieHeader($cookieHeader) — recover it from the ridebuilder_attribution cookie.
  • Capture::fromHeaders($headers, $name = 'X-RideBuilder-Click-Id') — from a forwarding header (decoupled path).

Client options

new RideBuilderClient(
    apiKey: $key,
    baseUrl: null,          // defaults to https://api.ridebuilder.com/v1
    maxRetries: 3,          // retries on network errors, timeouts, 5xx, 429
    timeoutMs: 10000,       // per-attempt timeout
    environment: 'production',
    transport: null,        // inject a RideBuilder\Affiliate\Transport\Transport (e.g. wrap a PSR-18 client)
);

reportCheckout / reportReturn return PostbackResult(accepted, status) (202 = accepted, validated asynchronously). Invalid input throws a non-retryable RideBuilderException; auth/size failures (401, 413) throw with ->status and ->errorCode. Amounts must be > 0 with at most 2 decimal places (pass a string to avoid float rounding) or the call throws up front.

Tests

Plain PHP, no PHPUnit/Composer required:

php tests/conformance.php   # the shared cross-language fixtures
php tests/unit.php          # 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 SDKs by the shared conformance fixtures.