Hanzo

Affiliates

Package affiliates is a partner program that pays commission on what your referrals spend.

Package affiliates is a partner program that pays commission on what your referrals spend.

Base URLhttps://api.hanzo.ai
Operations10
AuthAuthorization: Bearer $HANZO_API_KEY

affiliates

POST /v1/affiliates/apply

Enrolls the caller's OWN org as an affiliate at status applied, optionally requesting a vanity code, and answers the record — 201 on the first apply, 200 with created:false afterwards.

IDEMPOTENT, first apply wins: one affiliate per org, so re-applying never creates a second row and never resets an existing approval. Applying is not joining — no code is minted and nothing accrues until staff approve, which is where both the code and the commission rate come from.

The org is the validated caller's, never a field. A malformed vanity code is refused up front; the code is only REQUESTED here, and approval may mint a different one if the requested code is taken.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
requestedCodestringRequestedCode is the vanity code the applicant asks for; approval may mint a different one if it is taken.

POST /v1/affiliates/attribute

Records the first-touch edge every later commission is computed from: the caller's org was referred by the affiliate that owns this code.

The REFERRED org is the validated caller, never a field. A caller that could name the referred org could attach itself to somebody else's revenue. The affiliate is resolved from the code, and only an APPROVED affiliate's code resolves.

FIRST TOUCH WINS, set once: one affiliate per referred org, so a re-post answers the existing edge with created:false rather than moving the attribution. Self-attribution is refused, and so is a code that would make a cycle in the upline chain. An unknown code is a 404, deliberately: an affiliate code IS a public shareable link, so whether one is real is public by design, and the caller legitimately needs to know its link resolved.

A user-level mirror of the edge is written best-effort; a conflict there never fails the org attribution, which is the money-bearing one.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
codestringCode is the affiliate code the referred org arrived with.

POST /v1/affiliates/click

Counts a click on a share link. PUBLIC — it takes no principal, because a visitor clicking a shareable link has no session yet.

The ping folds into an in-memory buffer and NEVER writes the money database synchronously, so a click flood cannot contend with the accrual and payout write path; tallies are flushed in one batch on the next authenticated links read and at shutdown. Clicks are a vanity metric: no accrual and no payout ever reads them — those key on real metered spend — so click inflation cannot move money.

Any well-formed code is accepted WITHOUT checking that it exists, deliberately: this is not a code-existence oracle. counted reports that the buffer took the ping, not that the code is real; an unknown code simply no-ops at flush time.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
codestringCode is the share-link code that was clicked.

GET /v1/affiliates/leaderboard

Answers the top affiliates by lifetime accrued commission, shown by OPT-IN HANDLE with aggregate figures only, plus the caller's own exact rank.

It never discloses an org identity and never a referred org's usage. An affiliate that has set no handle still OCCUPIES its rank but is not listed — so opting out hides the name, not the position, and the visible board must not be read as a complete roster.

The caller's own row carries its exact GLOBAL rank, computed over the whole approved set rather than over the page, so it is right well outside the top of the board. Only an approved affiliate has a rank. Requires a validated principal; a signed-in non-affiliate may read the board but gets no personal row.

GET /v1/affiliates/me/earnings

Answers the caller's own commission ledger: per period, the margin it earned against and the commission taken from that margin; and per referred org, that referral's aggregate contribution. Integer cents throughout.

The per-org view deliberately carries the affiliate's OWN earned share and NOT the referred org's spend or margin. An affiliate is entitled to what it earned, not to a restatement of its customer's usage — the period view is where the margin base appears, aggregated across every referral.

Scoped server-side to the validated caller's affiliate; a caller that is not one gets isAffiliate:false.

POST /v1/affiliates/me/handle

Sets the caller's public leaderboard display name, or clears it.

The handle IS the opt-in. An empty handle opts out: the affiliate keeps its rank and can still see its own row, it simply stops being listed to anyone else. That is the whole privacy control — there is no separate visibility flag, and no way to be listed without choosing a name.

Requires a validated principal and an existing affiliate record; apply first. The handle is bounded and restricted to letters, digits, space, hyphen, underscore and dot.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
handlestringHandle is the public leaderboard display name; empty opts out.

Answers the caller's share links, each with its URL and its funnel: clicks tracked, signups — orgs attributed with that code — and conversions, meaning how many of those signups have actually produced commission.

Signups and conversions are DERIVED from the commission ledger and never stored, so they cannot drift from the money. Clicks are the one stored counter and the one that is pure vanity.

Any pending public click pings are folded into the store before the read, in one batch — which is how the counters stay current without a database write per click. Scoped to the validated caller's own affiliate; a non-affiliate gets isAffiliate:false and the link cap.

POST /v1/affiliates/me/links

Mints a new share link for the caller's own affiliate and answers it with its full URL, 201.

APPROVAL IS REQUIRED: an org that has applied but is not approved is refused, because a link that cannot accrue is a link that quietly loses the referral. A requested vanity code must be valid and free across the WHOLE directory — codes are one global namespace, so a taken code is a 409 rather than a silent alias. Omit the code and a random one is minted.

Bounded per affiliate. The label is cosmetic: it is trimmed, stripped of control characters and capped, and it is never part of a code.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
codestringCode is an optional vanity code; it must be free across the whole directory, and omitting it mints a random one.
labelstringLabel is cosmetic — trimmed, stripped of control characters, capped — and never part of a code.

GET /v1/affiliates/me

Answers the richer self-view: the same lifetime accrued, pending and paid commission and payout history, plus the caller's downline broken out by upline LEVEL — direct, second, third — each with the rate paid at that level and how many orgs sit there.

Commission is MULTI-LEVEL: a referred org's spend pays up its referral chain, three levels deep and no further. The direct level is the affiliate's own negotiated rate; the second and third are platform-wide switches, read live, so the schedule shown is the one actually in force rather than one compiled in. A caller that has not applied still gets that schedule alongside isAffiliate:false, so the console can show what it would earn.

Scoped to the validated org and nothing else, and refused without a principal. A PURE READ — it reports the downline but accrues nothing.

GET /v1/affiliates

Answers the caller org's OWN affiliate standing: status, referral code and share link, commission rate, how many orgs it has referred, and its lifetime accrued, still-pending and already-paid commission in integer cents, with its payout history.

An org that never applied gets an honest isAffiliate:false and the default rate rather than a 404 — the console renders the apply form off that answer.

The affiliate is resolved from the VALIDATED org, never from a field, so this can only ever read the caller's own row; without a principal it is refused. It is a PURE READ: nothing accrues until the sweep runs. Commission is earned on Hanzo's MARGIN, never on the referred customer's bill, so nothing here changes what that customer pays.


All Hanzo APIs · Interactive reference

How is this guide?

On this page