Skip to content

Programs

A program is the rule applied to clicks → conversions for a given destination. It’s where you set:

  • The destination URL the click lands on
  • The commission rule (percent or fixed, recurring or one-time, flat or varying with value or partner performance)
  • The attribution window + model
  • Optional start/end dates for promo periods

Each Link a partner shares belongs to exactly one program — that’s how the commission gets calculated.

Why programs aren’t always “one”

Most brands start with a single program called something like “Default 20% revshare” and never add another. That’s fine.

You’d add more programs when:

  • Different commission tiers — e.g. a “VIP affiliate” program with 30% recurring you only grant to a few hand-picked partners (see partner scoping)
  • Different products — a “Pro plan” program vs a “Basic plan” program with different destinations
  • Promo windows — a “Black Friday 2x commission” program that runs for 2 weeks then ends
  • Geographic targeting — different destinations for /us vs /eu

Creating a program

Admin → Programs → New program. Fields:

Name

Internal label — partners and creators don’t see this. Used in the admin UI.

Destination URL

Where the partner share-link lands when clicked. Required.

The router 302-redirects every click to this URL with a ?cref=<clickId> query param appended — that’s how the SDK on your site stitches the click back to the conversion.

To send the click id in a parameter your destination already reads, put {click_id} where it goes. The router substitutes it and appends no cref. A Stripe Payment Link, for example, only reads client_reference_id:

https://buy.stripe.com/abc123?client_reference_id={click_id}

Write it exactly as {click_id}: single braces, lower case, no spaces. It can go in the path, query or fragment, not the host. Any other brace text, such as {{click_id}}, {CLICK_ID} or {subid}, is rejected when you save, because the router would send it through as literal text. A buy.stripe.com destination without client_reference_id={click_id} saves with a warning, because no purchase through it can be credited. See Conversions by click id.

Comma-separated host allowlist. When set, partners can override the destination on their share-link as long as their override matches one of these hosts.

Example: destination is https://acme.com/, allowed deep-link domains is acme.com,docs.acme.com. Partner can deep-link to https://acme.com/pricing or https://docs.acme.com/getting-started, but not https://blog.acme.com/post or anywhere else.

Leave blank to lock destinations to whatever you set above — no deep linking allowed.

Commission rules

A program carries an array of sub-rules that combine to produce the partner payout. Each sub-rule has a trigger, an optional event type filter, a type (percent or fixed), and a value. Recurring sub-rules can carry a months cap.

Triggers:

  • On every — fires on every event matching the filter (or every event with a value if no filter is set; the legacy single-rule shape).
  • On first — fires only on the FIRST event of that type for the (partner, customer) pair. Used for one-time signing bonuses.
  • On every subsequent — fires on every event of that type EXCEPT the first. Pairs with On first to express dual-rate offers without the rules double-firing on event #1.

Event types: standard set is signup, trial_started, subscription_created, invoice_paid. A “Custom event…” escape hatch accepts any string for brands sending custom event names through the SDK.

Recurring + months cap: mark a sub-rule recurring and optionally cap how many months it keeps firing — measured from the first attributed event of that type for the partner + customer pair. Past the cap, no more commissions accrue. Null/blank = no cap (indefinite, bounded only by the program’s end date). Recurring rules keep paying on renewals after the attribution window closes. Rules that aren’t marked recurring pay only while the click is inside the window.

Examples:

OfferSub-rules
Flat 20% recurringevery / invoice_paid / 20% recurring
20% recurring, 12-month capevery / invoice_paid / 20% recurring × 12mo
$200 first-sale bonus + 20% recurringfirst / subscription_created / $200 fixed   +   every / invoice_paid / 20% recurring
50% on first invoice, 20% on every subsequent invoicefirst / invoice_paid / 50%   +   subsequent / invoice_paid / 20% recurring
$50 flat finder feefirst / signup / $50 fixed

When an event lands, the engine walks every sub-rule and emits one Commission row per match. A subscription_created event matching both a “first sale bonus” and an “every event with value” rule produces two commissions on the same Attribution — the partner sees both in their dashboard.

Rate varies: slabs and performance tiers

A sub-rule pays one flat rate unless you change Rate varies next to its rate:

  • Slabs by value — the rate depends on the event’s own value, e.g. up to 50,000 pays 10% and above 50,000 pays 15%.
  • Performance tiers — the rate depends on what the partner has already driven in this program, e.g. once their attributed revenue this month reaches 100,000, every further invoice pays 15%.

Either way, the rate field is the base: it applies up to and including the first threshold, or until the first tier is reached. Add up to 10 steps, each a threshold and a rate, with thresholds increasing from one step to the next.

Slabs pay in one of two ways:

ModeA 60,000 invoice, 10% up to 50,000, 15% above
The whole event at its slab’s rate (default). Works for percent and fixed rules; a fixed rule pays the slab’s amount.15% × 60,000 = 9,000
Each slice of the value at its own rate (marginal), like tax brackets. Percent rules only.10% × 50,000 + 15% × 10,000 = 6,500

A threshold is the top of the slab below it, so an event of exactly 50,000 pays the base rate. Events with no value, or a zero or negative value, pay the base rate. When several partners split a conversion, the slab is picked from the full event value, and each partner’s share of the result is paid as usual.

Tiers measure attributed revenue or attributed conversions (a conversion split 50/50 counts as half), over the partner’s lifetime, the calendar month (UTC) or a rolling window of 1–3650 days. They count one event type: the rule’s own, or one you pick. Only the partner’s earlier events in this program count, renewals included, and clicks flagged as fraud don’t. Refunds don’t lower the count.

Tiers aren’t retroactive. The event that takes a partner over a threshold is paid at the old rate, and the events after it at the new one. Earlier commissions are never recomputed.

A sub-rule can have slabs or tiers, not both. For both effects, use two sub-rules: their commissions add up as usual.

Thresholds in. Money thresholds are compared in each event’s own currency, which suits a single-currency program. Set a currency to pin them to one. OpenPartner doesn’t convert currencies, so an event in another currency pays a slab rule’s base rate, and a revenue tier only adds up events in the threshold currency.

Each commission records the slab or tier that set its rate, in its metadata (see API: Commissions). Per-partner terms (below) can use slabs and tiers too.

Revenue event types

Set on the program’s Edit form. invoice_paid and subscription_created events are always sales. List any other event types in this program that are sales, comma-separated, such as an order_paid you pay a fixed bounty on. Events that correct a sale, such as refund and chargeback, can’t be listed.

On the hosted plans, the value of a partner-attributed sale is the attributed revenue your platform fee is measured on. A self-hosted install isn’t metered, so the list changes nothing there.

Pay partners for the partners they recruit

Two-tier commissions, optional and off by default for each program. Tick Pay partners for the partners they recruit on the new-program or edit form, and a partner who recruited another partner earns a share of the commissions that recruit earns in this program.

  • Recruiter’s share (% of the recruit’s commission). Above 0 and up to 50%, at most two decimal places. At 10%, a recruit’s $50 commission earns their recruiter $5. The share is a percent of the recruit’s commission, not of the sale, so a recruiter never earns more than their recruit. It’s paid on top of the recruit’s commission, never out of it.
  • For how many months. 1–120, counted from the start of each recruitment: when the recruit applied through the link, or when the recruiter was set on them. Blank means for as long as the recruit earns.

Two levels, never more. If Ada recruits Ben and Ben recruits Cy, Ada earns on Ben and Ben earns on Cy, but Ada earns nothing on Cy. A share is paid on the commissions the program’s rules pay the recruit for their referrals, on whatever event they’re earned. Bonuses, performance bounties and recruiter commissions themselves don’t pay a share.

A partner gets a recruiter in one of two ways: they apply on your partner join page through another partner’s recruit link, or you set the recruiter on their partner page (see Recruiting). The recruiter doesn’t need access to this program. The program’s setting decides.

A recruiter commission is a commission like any other, on the recruit’s conversion:

  • It’s approved with the recruit’s commission, in the same step, whether you approve that one or its holdback ends. It has no holdback of its own, and its Approve button in the review queue stays disabled.
  • Refunds cut both. A refund reduces the recruit’s commission and the recruiter’s share in the same proportion, each the way refunds always work: an unpaid commission is reversed (and replaced, after a partial refund), and a paid one stays paid and gets a clawback.
  • Reversing the recruit’s commission reverses the share. If the share was already paid, it stays paid and is clawed back the way a refund of a paid commission is. You can also reverse a recruiter commission on its own.

Turning it on, or changing the share or the months, affects commissions accrued from then on. A recruiter only earns on events from after they became the recruiter. On the hosted plans, a recruiter commission counts toward the commission on that sale in your platform fee.

Keep the share small, and check that recruits bring in real customers. OpenPartner doesn’t check whether a recruit is the recruiter’s own second account, so review join-page applications and keep a holdback if you turn this on.

Customer reward (dual-sided incentives, optional)

Toggle Offer customer-side discount to add a reward for the referred customer. When set, every coupon code minted for a partner on this program also provisions a matching Stripe Coupon + Promotion Code so the discount applies automatically when the customer enters the code at your checkout. The partner still gets attribution + commission via the existing flow.

Three reward shapes:

  • % off — e.g. 25% off for 6 months
  • $ off — e.g. $20 USD off (currency required)
  • Free months — e.g. 1 month free (delivered as a 100% repeating Stripe coupon)

Duration:

  • First invoice only — single-use discount
  • Every invoice — applies to every renewal indefinitely
  • First N months — applies to the first N invoices then drops off

Without Stripe connected: the OpenPartner coupon still works for partner attribution; the discount just doesn’t auto-apply at checkout. You’d honor it manually. With Stripe connected (Connect Stripe on the hosted plan, your own Stripe key on a self-hosted install), no manual work — Stripe enforces the discount, a purchase with the code credits the partner, you get the new customer.

Let partners customize their coupon code

Toggle Let partners customize their coupon code to give each partner an “Add another code” affordance in their portal. Off by default — every partner gets the auto-generated code (e.g. ADALOVELACE5F2A) and only you can change it.

When on:

  • Partners can mint vanity codes like GRACIE15 or TIKTOKVIP from their dashboard
  • They can run multiple codes side-by-side per program (capped at 5 active per partner per program to keep your Stripe dashboard sane). Useful for audience-specific tracking — IG15 for Instagram, YT15 for YouTube
  • Each partner-side code provisions its own Stripe Coupon + Promotion Code, so the discount terms you set above apply automatically — partners only choose the string, never the discount
  • Codes are append-only. Renaming is “add new + deactivate old” as two clicks; the old code keeps redeeming until the partner explicitly retires it, so links and posts they already shared don’t break the moment they iterate

You can always override on a per-partner basis from Admin → Partners → [partner] → Coupons regardless of this toggle. Admin sees every code (active and deactivated) and can re-mint freely.

Attribution window

Decides which click wins a customer’s first conversion of each event type. You can set it anywhere from 1 to 365 days (attributionWindowDays in the API). 60 days is the default and matches what most affiliate programs use. Longer windows (90, 180, up to 365 days) attribute more conversions to partners but get more disputes and double-attribution edge cases. Shorter windows (7, 30 days) are stricter and pay less.

Once a partner wins that first conversion, every repeat of the same event type stays with them. The 2nd, 13th and 40th invoice_paid all go to the partners who won the first one, with the same split, for as long as the customer keeps paying. The age of the click doesn’t matter, and a later click on another partner’s link doesn’t take the renewals away.

Past the window, only sub-rules marked recurring pay, up to their months cap. A one-off bonus, or an On every rule that isn’t marked recurring, pays only while the click is inside the window. See Recurring + months cap.

A few cases worth knowing:

  • A new kind of conversion can follow a newer click. If the customer converts on an event type they’ve never converted on before (say, a first addon_purchased), the window decides it like any first conversion. A newer click from another partner can win it.
  • A late first payment stays with the partner. If the customer was already won on an earlier conversion, a first payment that lands after the window closes stays with the same partner. Example: signup on day 10, a 90-day trial, first invoice_paid on day 100.
  • A revoked partner stops earning renewals. Their share isn’t handed to the other partners in a split. If they were the only partner, the next renewal is decided by the window like a first conversion: another partner with a click in the window can win it, otherwise nobody is credited. Commissions already earned stay as they are.

Renewals stay with the partner who earned the customer

This checkbox, on the new-program and edit forms, turns the renewal behaviour above on or off per program. It’s on by default, including for programs created before it existed.

Turn it off and every payment is decided by the window alone. Your model credits each renewal from the clicks in the window, like a first conversion, and a renewal with no partner click in the window earns nobody a commission. That suits per-order retail programs where every purchase should follow the latest click. Changing it only affects events that arrive after the change. Commissions already earned stay as they are.

Attribution model

What happens when a conversion has multiple clicks in the window from different partners:

  • Last click — the most recent click gets 100%. Simple, predictable, the default for most programs. Most resembles “who closed the deal.”
  • First click — the very first click gets 100%. Rewards partners who introduced the brand, not the ones who closed it.
  • Linear — every click in the window splits the commission evenly. N clicks → 1/N each.
  • Position (40 / 20 / 40) — first + last click get 40% each, middle clicks split the remaining 20%. A compromise between first-click and last-click.

You can change the model later. Past commissions don’t recompute, but new conversions use the updated model. Renewals keep the split their first conversion got, so a partner who touches the customer later doesn’t join it.

Starts / Ends

Optional. Leave blank to run immediately and indefinitely.

  • Before Starts: program is hidden from partners (they can’t create new Links for it).
  • After Ends: existing Links keep redirecting (so already-shared posts don’t break), but no new commissions accrue for clicks past the end date. New Link creation is also blocked.

We email all participating partners + the brand admin 7 days before an end date so nobody gets surprised.

Editing a program

Each row has two per-row actions:

  • Edit — inline form with two sections:
    • Schedule: startsAt + endsAt. Useful for scheduling a program to start later, extending an end date past the original, or marking a program Ended at a specific past time.
    • Terms: the full commission rule editor (add/remove sub-rules, change triggers, set recurring caps, slabs and tiers), the customer reward toggle, the let partners customize their coupon code toggle, holdbackDays, revenue event types, the renewals checkbox and the recruiter share. Behind a banner that explains the snapshot semantics — see below.
  • End now — sets endsAt to the current time after a confirm. Hidden once the program is already Ended. Existing share-links keep redirecting (so creators’ embedded posts don’t break) — only new commission accrual stops, so it’s safe to fire.

Editing terms is safe — here’s why

OpenPartner snapshots commission terms (rate, recurring flag, holdback days) at the moment the brand approves the creator’s PartnershipRequest, as the creator’s terms for the program they were approved for. The snapshot lives on a PartnerCommission row on the brand’s instance, and commission accrual reads that value, not the live Program rule. So when you edit the Program’s rate from 20% to 10%:

  • Already-approved partners keep accruing at the rate they were quoted (20%)
  • New approvals get the new rate (10%)
  • Existing partnerships stay whole; you can lower a rate for new applicants without alienating creators already promoting you

This matches how mature affiliate networks (Impact, Partnerize, ShareASale) handle grandfathering. The banner above the Terms section is a reminder of this contract — edit freely, no creators get re-priced.

The recruiter share is the exception. It isn’t snapshotted per partner, so a change applies to every recruiter in the program, on commissions accrued from then on.

Per-partner commission overrides

For one-off cases, such as a VIP creator on a higher cut than the program default, use the Commission link on each partner’s row in Admin → Partners. A partner can have two kinds of custom terms:

  • Partner-wide default. Applies to every program the partner is in that doesn’t have its own terms.
  • Program terms. Apply to one program only. Each program the partner is granted has Set terms / Edit terms on the same page. On the partner’s Programs page, a Custom terms tag marks programs that have them.

Which terms a commission uses. Each commission belongs to the program the conversion came through. OpenPartner pays it on the first of these that exists:

  1. The partner’s terms for that program
  2. The partner’s partner-wide default
  3. The program’s own rule

The winning terms are used whole. Program terms replace the partner-wide default for that program; the two never mix.

Holdback follows the same terms. If the winning terms leave holdback blank, the program’s own holdback applies, not the partner-wide one. When you set program terms, the holdback field starts with the holdback that program uses today. Keep that value if you want a longer partner-wide holdback to carry over.

For example, Ada has a partner-wide default of 30% with a 60-day holdback, plus Starter program terms of $200 on the first subscription and 40% recurring, with holdback left blank.

Program (own holdback)Ada is paidHoldback
Starter (14 days)$200 on first subscription + 40% recurring, from her Starter terms14 days, Starter’s own, because her Starter terms leave it blank
Pro (30 days)30%, from her partner-wide default60 days, from her partner-wide default

The page lists each program with what it currently pays and where that comes from, so you don’t have to work this out by hand.

Network approvals save the offering’s terms as the creator’s terms for the offering’s program. If you later grant that creator another program, it pays that program’s rule, or your partner-wide default for them if you’ve set one, not the offering’s terms. Creators approved before program terms shipped (October 2026) have their offering terms saved as a partner-wide default; edit them there if you want them limited to one program.

Revoking a program leaves the partner’s terms for it in place, because links the partner already shared on it can keep earning. The program stays listed on the Commission page, marked “not granted”, until you clear its terms.

Clear override removes the partner-wide default. Clear program terms removes one program’s terms. Either way, those commissions fall back to the next item in the list above. Edits are stamped source = 'amendment' and replace any earlier approval-time or backfill snapshot for the same scope.

Past commissions aren’t recomputed when you set, change or clear terms. Only future events accrue at the new rate.

What’s still NOT editable here

destinationUrl, attributionWindowDays, attributionModel, deepLinkAllowedDomains. Reasons:

  • Destination URL — changing it redirects existing share-links to the new place, which is sometimes what you want and sometimes catastrophic. Today: publish a new program with the new destination. We’ll add inline editing once we surface a “this will change where N existing share-links land” preview.
  • Attribution window / model — these affect which clicks get credit, not the dollar amount. They’re shared across all partnerships of a program; snapshotting per-partnership would create surprising attribution divergence for clicks happening after an edit. The current “edit affects future events only, past Attribution rows stay” semantic is the honest model. The underlying PATCH /programs/:id accepts these fields if you want to edit via API. Shortening the window doesn’t take renewals away from partners who already won the customer.

Listing on the marketplace

Brands connected to the OpenPartner Network get two extra fields on each program:

  • shareOnNetwork — flip-on toggle. When ON, every save auto-publishes (or updates) the marketplace listing tied to this program. Defaults ON for new programs when the brand is connected; OFF for VIP / private programs you don’t want creators to discover.
  • marketplaceDescription — public copy shown on the discover card. Optional — when empty, the card renders without a description block.

That’s the whole brand-side surface. Title comes from the program’s name. Commission line is auto-derived from the rule + customer reward (no freeform “make-up your own copy” input — the listing is always faithful to what the engine will actually pay). Attribution window, holdback, end date, and customer reward all snapshot from the program at save time. Toggle off later → the listing flips to unpublished but isn’t deleted, so flipping back on restores it intact.

The previously-separate “Network → Offerings” admin page is gone — there’s nothing to manage there that isn’t already on the program. The Offering row still exists on the Network’s database as the marketplace’s storage; it’s just no longer something brand admins interact with directly.

Lifecycle states

A program at any moment is one of:

  • Scheduled — startsAt is in the future. Hidden from partners, no Link creation, no attribution.
  • Active — running. Normal behavior.
  • Ended — endsAt is in the past. Existing Links still redirect; no new commissions or Link creation.

The admin UI shows the state with a colored pill on each program row. We email all participating partners + the brand admin 7 days before an end date so nobody gets surprised; pushing endsAt further out clears that flag so the warning re-fires for the new window.

Per-partner programs

Sometimes a brand wants a special program for a single partner — say, a 30% revshare for a high-volume creator. Two ways:

  1. Create the program, leave “Grant to all existing partners” unchecked. Then on the partner’s row → Programs → tick the new program.
  2. Create the program first, invite the partner second. When inviting, uncheck “Grant access to all current campaigns” and pick only the new one.

See invite partners for the full scoping flow.