SDKs

Official SDKs for TypeScript, Python, Ruby, Go, PHP, Swift and Kotlin: typed, retrying, idempotent, generated from the OpenAPI document.

Embed
Preview of the card
<a href="https://referalli.com/docs/sdks"><img src="https://referalli.com/docs/_api/public/orgs/07f432f4-34b9-46a7-aaad-c0e395d2e4f9/spaces/2bf4f614-3630-4fbf-85f9-5ecafa6b7d97/pages/9cc0783f-0559-40e3-8eaa-12c82c94ecd9/social-card.svg?v=3e7ae33eec8b" alt="SDKs" width="600" height="315"></a>

Every server SDK wraps the same /v1 API and is generated from its OpenAPI document, so each one has a typed method for every operation, typed models, and an error class for every error code. All of them are dependency-free.

Language

Install

Package

Client

TypeScript / JavaScript

npm install @referally/sdk-js

npm

ReferallyClient

Python 3.11+

pip install referally

PyPI

Referally

Ruby 3.1+

gem install referally

RubyGems

Referally::Client

Go 1.23+

go get github.com/referally/referally-go

pkg.go.dev

referally.New

PHP 8.1+

composer require referally/referally-php

Packagist

Referally\Client

Swift (macOS 12 / iOS 15+)

SwiftPM: https://github.com/referally/referally-swift

Swift Package Index

ReferallyClient, ReferallyTracker

Kotlin / JVM 17+

implementation("io.referally:referally-kotlin:1.0.0")

Maven Central

ReferallyClient, ReferallyTracker

Pass the host without /v1 as the base URL (it defaults to the hosted API). Never ship an rk_ key inside a browser or mobile app: use the server SDKs on your backend; the Swift and Kotlin ReferallyTracker use only the public tracking token.

What every SDK does the same way

Each SDK passes the same conformance plan (packages/sdk-conformance), run against a mock server in CI:

  • One method per operation, named after its operationId without V1: getPartnersId, postReferralsAssociate, get_referrals in Python and Ruby, GetPartnersID in Go. Path params come first, then the body, then query params.

  • Typed models for every schema: TypedDicts (Python), RBS signatures (Ruby), PHPStan type aliases (PHP), structs (Go), Codable structs (Swift), data classes (Kotlin).

  • Typed errors: each documented error code has its own class (ValidationError, NotFoundError, RateLimitedError, ReplayError, …) carrying code, status, message, requestId, docsUrl, details and retryAfter. Unknown codes fall back to the base API error class.

  • Retries: 429 and 5xx responses and network errors are retried up to 3 times with exponential backoff (500 ms, doubling, with jitter), honoring Retry-After. 4xx errors are never retried.

  • Idempotency: every POST carries an Idempotency-Key, generated unless you pass one, and the same key is reused on every retry, so a retried create never runs twice.

  • Pagination: list methods return one page (data, has_more, next_cursor); …Each / …_iter / …_each iterate every item, following starting_after.

  • Versioning: requests send referally-version: 2026-11-01, the version the SDK was generated against; each client lets you pin another.

  • Webhooks: a Standard Webhooks verifier that rejects deliveries older than 5 minutes and accepts either secret during a rotation.

Server SDKs

import { ReferallyClient } from '@referally/sdk-js';

const referally = new ReferallyClient({ apiKey: process.env.REFERALLY_API_KEY! });

const { referral } = await referally.associate({
  programId: 'prg_...',
  customerRef: stripeCustomer.id,
  anonId: form.referally_anon_id,
  referralToken: form.referally_click_id || undefined,
  idempotencyKey: `signup:${user.id}`,
});
for await (const r of referally.list('/v1/referrals', { status: 'active' })) console.log(r.id);

Errors are typed in every language; catch the specific class you care about:

try:
    client.get_partners_id("ptr_missing")
except NotFoundError as e:
    print(e.code, e.request_id, e.docs_url)

Any operation can also be called by its id (client.call("getPartnersId", path=…) in Python, client.Call(ctx, "getPartnersId", …) in Go, and so on), and list_all / ListAll iterate any list operation.

Publishing

Each SDK is released by pushing a tag: py-v1.2.3, rb-v1.2.3, js-v1.2.3, php-v1.2.3, go-v1.2.3, swift-v1.2.3 or kt-v1.2.3 (.github/workflows/sdk-publish.yml). The generated layer is rebuilt with pnpm --filter @referally/sdk-js gen, and CI fails when any SDK is stale against the API.

TypeScript types for every endpoint

@referally/sdk-js/types has a type for every component in the OpenAPI document (Program, Partner, Referral, CommissionEvent, Settlement…). Each operation gets <Name>Body, <Name>Query and <Name>Response types, where the name is the method and path without /v1: PostReferralsAssociateBody, GetPartnersResponse. An operations table maps every operationId to its method and path:

import { operations, type PostReferralsAssociateBody, type AssociateResponse } from '@referally/sdk-js/types';

const body: PostReferralsAssociateBody = { programId: 'prg_...', customerRef: stripeCustomer.id };
const { method, path } = operations.postV1ReferralsAssociate;
const res = await fetch(`https://referalli.com${path}`, {
  method,
  headers: { authorization: `Bearer ${process.env.REFERALLY_API_KEY}`, 'content-type': 'application/json' },
  body: JSON.stringify(body),
});
const { referral } = (await res.json()) as AssociateResponse;

The types are generated from the API's own route schemas, and a test fails when they fall behind, so they match the server. Other generators (openapi-typescript, openapi-generator) work from /v1/openapi.json too.

Auth.js / NextAuth adapter

referallyAuthEvents returns a createUser handler for Auth.js. It hashes the new user's email, reads the referral context you stored, and calls associate with idempotency key authjs:{userId}. Failures never block signup.

import { ReferallyClient, referallyAuthEvents } from '@referally/sdk-js';
import { cookies } from 'next/headers';

const client = new ReferallyClient({
  apiKey: process.env.REFERALLY_API_KEY!,
  baseUrl: 'https://referalli.com',
});

const referallyEvents = referallyAuthEvents(client, {
  programId: 'prg_...',
  getReferral: () => JSON.parse(cookies().get('referally_ctx')?.value ?? '{}'),
});

// In your Auth.js config:
// events: { createUser: referallyEvents.createUser }

referally_ctx is the first-party cookie the tracking script writes, so reading it on your server gives you anonId, clickId and code. The customerRef used is the Auth.js user id (or email when there is no id); see the note on matching billing ids.

Mobile trackers

ReferallyTracker for Swift and Kotlin persists an anonymous id on the device and calls the public visit and identify endpoints with your tracking token. It does not use an API key.

let tracker = ReferallyTracker(
    trackingToken: "tk_...",
    baseURL: URL(string: "https://referalli.com")!
)
tracker.trackVisit(code: deepLinkCode)      // on app open from a referral deep link
tracker.identify(customerRef: user.id)      // after signup

Send tracker.anonId to your backend at signup and pass it to associate there.

In-app purchases

Purchases create commissions, so they're reported from your server, never from the app: the app only holds the public tracking token. Send the App Store or Google Play receipt to your backend, validate it, then report the purchase with your API key. Each eventId is processed once.

curl -X POST https://referalli.com/v1/mobile/purchases \
  -H "Authorization: Bearer $REFERALLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"eventId":"GPA.1234-5678","customerRef":"user_42","amountMinor":999,"currency":"usd","productRef":"pro_monthly"}'

amountMinor is positive; for a refund send "type": "refund" with the refunded amount. The response has conversions, linesCreated and reversals. The old public POST /t/{token}/mobile/event endpoint answers 410 Gone.

MCP server

packages/mcp is a Model Context Protocol server that gives an AI assistant access to your program through your API key: read tools, plus write tools that only act after a confirmed second call (see CLI and MCP). It runs over stdio from a checkout of the repository:

REFERALLY_API_KEY=rk_... \
REFERALLY_API_URL=https://referalli.com \
pnpm --filter @referally/mcp start

REFERALLY_API_URL defaults to http://localhost:4000; the server exits if REFERALLY_API_KEY is not set. Its read tools take no arguments:

Tool

Calls

list_programs

GET /v1/programs

program_overview

GET /v1/analytics/overview?days=30

partner_performance

GET /v1/reports/partner-performance

list_referrals

GET /v1/referrals

list_fraud_cases

GET /v1/fraud/cases?status=open

Updated