Refficks API reference
What your own server builds on: report events, and manage partners, programs, links and codes with an API key. Commissions and payouts are read only: no endpoint approves or pays one.
Before your first call
- Address
https://go.refficks.com/api/v1, then the path below.- Key
Every request sends
Authorization: Bearerand a secret key, made on the API keys screen in Refficks.- The whole file
- openapi.json, OpenAPI 3.1, for Postman, Insomnia or a client generator.
Your key
get/server/me
Whose key this is
The organization the key belongs to, and the key's name, purpose (zapier, make, n8n, or null for a key made on the API keys screen) and abilities, each with a label in words. An automation platform shows this as the connection's name. Nothing in it is part of the key, and any secret key may call it (identify).
Answers
Events
post/events
Ingest a normalized event
The server-side ingest endpoint. Authenticated with an API key, not a session.
Idempotent: the Idempotency-Key header is required. Replaying the same key with the same payload returns the original event and "status": "duplicate". Reusing it with a different payload is a 409.
Processing is asynchronous: the response acknowledges receipt, it does not report attribution or commission outcomes.
Parameters
| Name | In | What it is |
|---|---|---|
Idempotency-Keyrequired | header | string |
Body: EventInput
| Field | What it is |
|---|---|
event_typerequired | one of "tracking.visit", "tracking.click", "customer.created", "customer.updated", "lead.created", "trial.started", "subscription.created", "subscription.updated", "subscription.cancelled", "invoice.created", "invoice.paid", "invoice.payment_failed", "order.created", "order.refunded", "payment.refunded", "payment.disputed", "payment.dispute_closed", "credit_note.issued" What a merchant's own server may report. The line is what the caller is in a position to know. Your system knows what happened in your business. It is not in a position to report what Refficks decided, so the conversion the attribution engine writes, and the lead, deal-registration and opportunity lifecycle Refficks records when somebody acts on a screen, are refused here with a message naming what to send instead. This list is generated from |
external_id | string |
occurred_atrequired | string (date-time) |
customer | object |
properties | object Normalized payload. Monetary values are integer minor units with an explicit currency. |
Answers
Partners
get/server/partners
List partners
Oldest first, tie-broken on the key. A server walks the whole list, and a newest-first page shifts under a paginating caller every time a partner is added: page two repeats a row from page one and drops another. Ascending by a key that only grows means a page already read stays read.
Parameters
| Name | In | What it is |
|---|---|---|
page | query | integer |
per_page | query | integer |
status | query | PartnerStatus |
lifecycle_stage | query | PartnerLifecycleStage |
email | query | string (email) An exact address, case-insensitive. |
Answers
post/server/partners
Add a partner
Nobody is emailed unless the request says so. No portal invitation is sent by default; pass send_portal_invitation: true for one. A person pressing Add Partner is adding one person and watching; a server is a loop, and a first sync that mails two thousand people (several hundred of whom left years ago) cannot be un-sent.
organization_id is never accepted. The tenant comes from the key, and supplying it is a validation error rather than a silently ignored field.
status is refused. A partner created already archived would have a status nobody set and no audit entry could explain; archiving is its own call.
Body
| Field | What it is |
|---|---|
emailrequired | string (email) |
first_name | string or null |
last_name | string or null |
company_name | string or null |
phone | string or null |
country | string ISO 3166-1 alpha-2, checked against the list. Case does not matter. |
timezone | string or null |
website | string (uri) or null |
roles | array of PartnerRole |
tags | array of string |
lifecycle_stage | one of "applicant", "approved" Only the two stages that mean something at the moment of arrival. The later ones (onboarded, growing, dormant, at risk) are conclusions drawn from what a partner did, and a record with no history cannot be one. They are reached through |
send_portal_invitation | boolean |
Answers
get/server/partners/lookup
Find one partner by something you already have
Exactly one of email or code. Both, or neither, is a 422: "either, and I will guess" is how a lookup quietly answers the wrong question when the two disagree.
A single object or a 404, never a list of length zero or one. An integration should not have to store Refficks' ids to use Refficks, and should not have to unwrap an array to find that out.
code matches any tracking link of theirs, including a retired one: a code out of a year-old newsletter still identifies whose it was.
Parameters
| Name | In | What it is |
|---|---|---|
email | query | string (email) |
code | query | string |
Answers
get/server/partners/{partner}
Read one partner
Parameters
| Name | In | What it is |
|---|---|---|
partnerrequired | path | Ulid |
Answers
patch/server/partners/{partner}
Change a partner's details
A genuine partial update: a field sent as null is cleared, a field not sent is untouched.
Details only. status, lifecycle_stage, roles and currency are refused with a message naming the endpoint that does the job: refused rather than ignored, because a silently dropped field returns a 200 and a partner object, and the caller ships. The bug then surfaces months later against the one partner where it mattered.
The scores are refused too. They are computed, and a score a client can set is a score no recommendation built on it means anything.
Parameters
| Name | In | What it is |
|---|---|---|
partnerrequired | path | Ulid |
Body
| Field | What it is |
|---|---|
first_name | string or null |
last_name | string or null |
company_name | string or null |
phone | string or null |
country | string or null |
timezone | string or null |
website | string (uri) or null |
Answers
post/server/partners/{partner}/transition
Move a partner between lifecycle stages
Separate from PATCH because a stage change is a decision with consequences (it fires automations, it stamps approved_at, it is what lets somebody into the portal), and an edit to a field is not.
The legal moves are the same ones a person gets. An illegal one is a 409, so a server cannot walk a partner around the funnel a screen would refuse to.
Parameters
| Name | In | What it is |
|---|---|---|
partnerrequired | path | Ulid |
Body
| Field | What it is |
|---|---|
lifecycle_stagerequired | PartnerLifecycleStage |
reason | string or null |
Answers
post/server/partners/{partner}/archive
Archive a partner
Archiving, not deleting. A partner is attached to conversions, ledger entries and payouts; removing the row would make last quarter unreconcilable. It also stops their tracking: an archived partner's links stop earning.
Security review F-25: refused with 403 to a key made for an automation platform, and so is restoring.
A POST to a named path rather than a DELETE, because DELETE promises removal and this keeps everything.
Erasure is deliberately absent from this surface. It takes a typed confirmation from somebody who has read the sentence saying it cannot be undone, and a token cannot read a sentence.
Parameters
| Name | In | What it is |
|---|---|---|
partnerrequired | path | Ulid |
Answers
post/server/partners/{partner}/restore
Put an archived partner back
Their programme memberships are deliberately untouched, here as on the screen: restoring must not reinstate a programme the merchant suspended on purpose before archiving them. Two decisions, and only one of them is being undone.
Parameters
| Name | In | What it is |
|---|---|---|
partnerrequired | path | Ulid |
Answers
Programs
get/server/programs
List programmes
Parameters
| Name | In | What it is |
|---|---|---|
page | query | integer |
per_page | query | integer |
status | query | ProgramStatus |
module | query | ProgramModule |
Answers
post/server/programs
Create a programme
slug is derived from the name and cannot be chosen here: uniqueness is per organization and there is nothing to check against until the programme exists. It is editable afterwards.
Set default_destination_url: without it every link you later mint has to carry the same URL again, and a link with nowhere to go is refused.
Body
| Field | What it is |
|---|---|
namerequired | string |
description | string or null |
module | ProgramModule |
status | ProgramStatus |
default_currency | string |
attribution_window_days | integer How long after a click a sale still credits the partner, what other platforms call the cookie duration. |
auto_approve_partners | boolean |
terms_url | string (uri) or null |
default_destination_url | string (uri) or null |
Answers
get/server/programs/{program}
Read one programme
Parameters
| Name | In | What it is |
|---|---|---|
programrequired | path | Ulid |
Answers
patch/server/programs/{program}
Change a programme's settings
module is refused: it decides which half of the product a programme belongs to, so changing it would leave everything already recorded under the old one belonging to nothing.
Rates are not here: a key may set no rate, so commission plans are read only.
Parameters
| Name | In | What it is |
|---|---|---|
programrequired | path | Ulid |
Body
| Field | What it is |
|---|---|
name | string |
description | string or null |
slug | string |
status | ProgramStatus |
default_currency | string |
attribution_window_days | integer How long after a click a sale still credits the partner, what other platforms call the cookie duration. |
auto_approve_partners | boolean |
terms_url | string (uri) or null |
default_destination_url | string (uri) or null |
Answers
get/server/programs/{program}/partners
Who is in a programme
Parameters
| Name | In | What it is |
|---|---|---|
programrequired | path | Ulid |
page | query | integer |
per_page | query | integer |
status | query | ProgramPartnerStatus |
partner_id | query | Ulid |
Answers
post/server/programs/{program}/partners
Enrol a partner
A tier may be chosen here and not changed afterwards: a tier sets what somebody earns, and a key may set no rate, so a PATCH naming one is refused.
Two things to know before your first script. A partner created while the merchant has exactly one programme is already in it, so enrolling them again is a 409; enrolment is deliberately not idempotent, because a second call that meant to change something and silently did nothing is worse than a conflict you can read. And enrolling somebody mints their first tracking link.
Parameters
| Name | In | What it is |
|---|---|---|
programrequired | path | Ulid |
Answers
patch/server/programs/{program}/partners/{membership}
Suspend a membership, or restore it
status only. tier_id and custom_commission_plan_id are refused with a message naming where they are set. Both decide what somebody earns, and a key may set no rate.
Body
| Field | What it is |
|---|---|
statusrequired | ProgramPartnerStatus |
Answers
Commission plans
get/server/programs/{program}/commission-plans
What a programme pays (read only)
There is no POST here, and the absence is the decision. A plan sets what everybody earns, and nobody has said a token may set a rate. A write is a 405: the address is real and the method is not.
Ordered by priority, which is the order that decides which plan pays: a merchant reading this list is almost always asking which one applies.
Parameters
| Name | In | What it is |
|---|---|---|
programrequired | path | Ulid |
page | query | integer |
per_page | query | integer |
Answers
Tracking links
get/server/tracking-links
List tracking links
Parameters
| Name | In | What it is |
|---|---|---|
page | query | integer |
per_page | query | integer |
partner_id | query | Ulid |
program_id | query | Ulid |
status | query | TrackingStatus |
code | query | string An exact code. |
Answers
post/server/tracking-links
Mint a link for a partner
The partner must already be in the programme: a link's terms come from the membership, so a link without one is a link nobody could state the rate for. Enrolling a partner also mints their first link, so this is for the second and after.
With no destination_url, the programme's default_destination_url is used. With neither, the request is refused.
Body
Answers
patch/server/tracking-links/{link}
Rename, repoint or retire a link
code is refused. It is printed in videos, bios and newsletters, so renaming it would silently break every place a partner already shared it, and a script could do that to two hundred people in one call. Retire this link (status: archived) and mint another.
partner_id and program_id are refused too: moving a link would reassign the clicks it has already recorded.
Parameters
| Name | In | What it is |
|---|---|---|
linkrequired | path | Ulid |
Body
| Field | What it is |
|---|---|
name | string or null |
destination_url | string (uri) |
attribution_window_days | integer or null |
status | TrackingStatus |
Answers
Coupon codes
get/server/coupon-codes
List coupon codes
Parameters
| Name | In | What it is |
|---|---|---|
page | query | integer |
per_page | query | integer |
partner_id | query | Ulid |
program_id | query | Ulid |
status | query | TrackingStatus |
code | query | string |
Answers
post/server/coupon-codes
Make a code for a partner
This does not create a discount in your payment provider. Refficks connects to Stripe as a platform and holds no credential of yours. What this creates is the record that says this code belongs to this partner.
To register a promotion code you already made, send external_promotion_id, with account_id naming which connected account holds it when you have more than one.
Security review F-15: Stripe is asked what the promotion's code is, and a claim whose code is not this code is refused with 422; a promotion another code already claims is refused with 409. A key made for an automation platform cannot claim one at all (403), nor switch a code or link on or off.
code is optional: left out, one is derived from the partner's name, which is what a server looping over two hundred partners wants.
One code per partner per programme, unless the merchant has turned on more than one. A second is a 409.
Body
Answers
get/server/coupon-codes/{coupon}
Read one code
Parameters
| Name | In | What it is |
|---|---|---|
couponrequired | path | Ulid |
Answers
patch/server/coupon-codes/{coupon}
Change a code's limits or where it is placed
code is refused, for the reason a link's is: it is what somebody types at the checkout. Retire this one and make another.
uses_count is refused because it is Refficks' count of redemptions: a merchant who could edit it could hand somebody another fifty uses with no record of having done so.
Sending external_promotion_id: null takes a placement back, which is a different instruction from not sending the field at all.
Parameters
| Name | In | What it is |
|---|---|---|
couponrequired | path | Ulid |
Body
| Field | What it is |
|---|---|
status | TrackingStatus |
attribution_priority | integer |
max_uses | integer or null |
expires_at | string (date-time) or null |
minimum_amount | integer or null Minor units. Null means the programme's default applies, not "no minimum". |
minimum_amount_currency | string or null |
first_time_transaction | boolean or null |
external_promotion_id | string or null |
account_id | string or null |
Answers
Commissions
get/server/commissions
Read the ledger (read only)
occurred_from / occurred_to filter on occurred_at, not created_at: a sale in March recorded in April belongs to March's books.
Paged by id, because a ULID only grows while occurred_at does not: a late-arriving event carries an older date and would insert rows behind a crawler.
No total. A ledger holds several currencies and this API will not sum across them; a figure nobody can spend is worse than none.
Parameters
| Name | In | What it is |
|---|---|---|
page | query | integer |
per_page | query | integer |
partner_id | query | Ulid |
program_id | query | Ulid |
payout_id | query | Ulid |
status | query | CommissionEntryStatus |
type | query | CommissionEntryType |
currency | query | string |
occurred_from | query | string (date) |
occurred_to | query | string (date) |
Answers
get/server/commissions/{entry}
Read one ledger entry (read only)
Parameters
| Name | In | What it is |
|---|---|---|
entryrequired | path | Ulid |
Answers
Payouts
get/server/payouts
Read payouts (read only)
There is no POST. Refficks moves no money: a payout's status is recorded and the merchant downloads a file for their bank, so there is no transfer for an endpoint to trigger. Read status: paid as the merchant recorded that they sent it.
Parameters
| Name | In | What it is |
|---|---|---|
page | query | integer |
per_page | query | integer |
partner_id | query | Ulid |
status | query | PayoutStatus |
currency | query | string |
Answers
get/server/payouts/{payout}
Read one payout (read only)
Parameters
| Name | In | What it is |
|---|---|---|
payoutrequired | path | Ulid |
Answers
get/server/payouts/{payout}/entries
What a payout is made of (read only)
The question a reconciling merchant actually has, answered without making them filter the whole ledger by a payout id and trust that they got all of it.
Parameters
| Name | In | What it is |
|---|---|---|
payoutrequired | path | Ulid |
page | query | integer |
per_page | query | integer |
Answers
Subscriptions
get/server/hooks
List this key's subscriptions
The subscriptions this key made, oldest first, never the merchant's own receivers and never another key's. Needs hooks:manage. Each has url_hint (host and last four characters), never the address.
Answers
post/server/hooks
Subscribe to be told
What a REST-hook subscribe sends: {url, event} or {url, events: [...]}, optional description. The address is kept encrypted. Asking again for the same address from the same key answers the same subscription (200, no secret) and starts it again if it had ended; asking from another key while it is live is a 409. Every event needs partners:read; commission and payout events need money:read too (403 naming the ability). At most 200 active per key.
Answers
get/server/hooks/events
What may be subscribed to
Every event something in the product raises, with label, needs (the abilities it takes) and subscribable for this key: the dropdown an automation platform shows.
Answers
get/server/hooks/samples
What an event looked like recently
Up to three of the merchant's own newest facts for event, newest first, in the shape a delivery has (docs/events.md, "Delivered outward") and with the same id a live delivery of the same fact carries. An empty list when there is nothing yet; nothing is invented. Needs hooks:manage and the read ability the event carries.
Parameters
| Name | In | What it is |
|---|---|---|
eventrequired | query | string |
Answers
get/server/hooks/{hook}
One of this key's subscriptions
Parameters
| Name | In | What it is |
|---|---|---|
hookrequired | path | string |
Answers
delete/server/hooks/{hook}
Unsubscribe
Ends it and keeps it, with its delivery log; nothing more is sent. A second call is answered the same, because platforms retry.
Parameters
| Name | In | What it is |
|---|---|---|
hookrequired | path | string |
Answers
Objects
CommissionEntryStatus
CommissionEntryType
Error
| Field | What it is |
|---|---|
error | object |
EventInput
| Field | What it is |
|---|---|
event_typerequired | one of "tracking.visit", "tracking.click", "customer.created", "customer.updated", "lead.created", "trial.started", "subscription.created", "subscription.updated", "subscription.cancelled", "invoice.created", "invoice.paid", "invoice.payment_failed", "order.created", "order.refunded", "payment.refunded", "payment.disputed", "payment.dispute_closed", "credit_note.issued" What a merchant's own server may report. The line is what the caller is in a position to know. Your system knows what happened in your business. It is not in a position to report what Refficks decided, so the conversion the attribution engine writes, and the lead, deal-registration and opportunity lifecycle Refficks records when somebody acts on a screen, are refused here with a message naming what to send instead. This list is generated from |
external_id | string |
occurred_atrequired | string (date-time) |
customer | object |
properties | object Normalized payload. Monetary values are integer minor units with an explicit currency. |
Money
Minor units plus an ISO-4217 currency. Never a float.
| Field | What it is |
|---|---|
amount | integer |
currency | string |
PaginatedEnvelope
| Field | What it is |
|---|---|
data | array of object |
meta | object |
links | object |
PartnerLifecycleStage
PartnerRole
PartnerStatus
PayoutStatus
ProgramModule
ProgramPartnerStatus
ProgramStatus
ServerCommissionEntry
One line of a merchant's ledger. Read only.
An entry carries its own arithmetic: amount, the base_amount it was worked out from, and the rate. A merchant reconciling should be able to see that £14.25 is ten per cent of £142.50 rather than take the figure on trust.
A reversal is a new entry, never an edit: a refund writes a negative row whose parent_entry_id points at the original, and both stay.
| Field | What it is |
|---|---|
objectrequired | "commission_entry" |
idrequired | Ulid |
partner_idrequired | Ulid |
program_idrequired | Ulid or null |
commission_plan_idrequired | Ulid or null |
event_idrequired | Ulid or null The event this was worked out from, which ties our ledger to the merchant's own system. |
customer_idrequired | Ulid or null |
parent_entry_idrequired | Ulid or null The entry this one undoes, for a reversal. |
typerequired | CommissionEntryType |
statusrequired | CommissionEntryStatus |
currencyrequired | string Governs both amounts. Entries in different currencies are never summed. |
amountrequired | integer Minor units. Negative on a reversal. |
base_amountrequired | integer or null What the rate was applied to. Null where the entry is not a percentage of anything. |
raterequired | number or null A percentage (ten, not 0.1). Null alongside a null |
descriptionrequired | string or null |
plan_namerequired | string or null The plan name recorded at the time. This is a ledger; it says what it said. |
payout_idrequired | Ulid or null |
occurred_atrequired | string (date-time) Never null. An entry that did not know when it happened could not be placed in a period, so the column does not allow one. |
approved_atrequired | string (date-time) or null |
paid_atrequired | string (date-time) or null |
created_atrequired | string (date-time) or null |
ServerCommissionPlan
What a programme pays. Read only: a key may set no rate, so a POST or PATCH here is a 405.
rules is published verbatim because the rules are the plan: a payload saying type: tiered and declining to say what the tiers were would answer a question nobody asked. The shape inside it belongs to the calculation engine, so changing that shape changes this contract.
| Field | What it is |
|---|---|
objectrequired | "commission_plan" |
idrequired | Ulid |
program_idrequired | Ulid |
namerequired | string |
descriptionrequired | string or null |
typerequired | one of "percentage", "fixed", "tiered", "hybrid" |
currencyrequired | string |
recurringrequired | boolean |
duration_monthsrequired | integer or null Null means for as long as the subscription lasts, a different claim from a number. |
auto_approve_after_days | integer or null Days after a sale its commission approves itself, or null when a person approves each one. Read-only: setting it is approving money in advance, which only an admin does, in the dashboard. |
priorityrequired | integer Which plan wins when several could apply. Lower goes first. |
statusrequired | string |
rulesrequired | object |
created_atrequired | string (date-time) or null |
updated_atrequired | string (date-time) or null |
ServerCouponCode
The code a partner's audience types at the checkout. This is the Refficks record, not a discount in anybody's payment provider.
| Field | What it is |
|---|---|
objectrequired | "coupon_code" |
idrequired | Ulid |
program_idrequired | Ulid |
partner_idrequired | Ulid |
coderequired | string |
providerrequired | string or null |
attribution_priorityrequired | integer Which code wins when a basket carries more than one. |
statusrequired | TrackingStatus |
max_usesrequired | integer or null |
uses_countrequired | integer Refficks' count of redemptions. Never writable. |
expires_atrequired | string (date-time) or null |
minimum_amountrequired | integer or null Minor units. Null means the programme's default applies, not "no minimum". A client reading null as zero is wrong about every code the merchant never overrode. |
minimum_amount_currencyrequired | string or null |
first_time_transactionrequired | boolean or null |
placementsrequired | array of ServerCouponPlacement Per connected account, because a merchant may have several and no single boolean could honestly answer for both. Empty is the ordinary case. |
created_atrequired | string (date-time) or null |
updated_atrequired | string (date-time) or null |
ServerCouponPlacement
This code, as it exists in one connected payment account. Refficks holds no credential, only the non-secret acct_… id.
| Field | What it is |
|---|---|
objectrequired | "coupon_placement" |
providerrequired | string or null |
integration_idrequired | Ulid or null |
account_idrequired | string or null The account the code is in, as recorded when it was placed, still named after that account is disconnected, when the code is paused rather than gone. |
external_promotion_idrequired | string or null |
ServerOwnRate
A partner's own figure on one rule. What the rule covers (its conditions) is the rule's; only the figure is the partner's.
| Field | What it is |
|---|---|
commission_plan_idrequired | Ulid |
typerequired | one of "percentage", "fixed" |
valuerequired | number A percentage, or for |
discounted_valuerequired | number or null Their figure on a sale with a discount code, when they were given one. Null keeps the rule's. |
currencyrequired | string or null The rule's currency. |
appliesrequired | boolean Whether this figure is what the rule pays them today. |
not_applying_becauserequired | one of "rule_archived", "rule_pays_differently" or null
|
reasonrequired | string or null The merchant's note on why. |
set_atrequired | string (date-time) or null |
ServerPartner
A partner as the management API publishes one.
Distinct from Partner, which is the dashboard's shape and follows its screens. Every property below is always present; absent data is null, never missing. Within v1 properties are added and never removed or repurposed.
The scores (score, potential_score, risk_score) are deliberately absent: they are recomputed on a schedule we change, against a scale nobody outside has agreed to, and automating against one would be automating against an implementation detail.
| Field | What it is |
|---|---|
objectrequired | "partner" |
idrequired | Ulid |
statusrequired | PartnerStatus |
lifecycle_stagerequired | PartnerLifecycleStage |
emailrequired | string (email) |
first_namerequired | string or null |
last_namerequired | string or null |
company_namerequired | string or null |
phonerequired | string or null |
countryrequired | string or null ISO 3166-1 alpha-2, stored upper-case. |
timezonerequired | string or null |
websiterequired | string (uri) or null |
currencyrequired | string ISO 4217. The currency both amounts below are in. On the object rather than implied, because a figure without its currency is a figure somebody will add to another one. |
lifetime_revenue_amountrequired | integer Minor units (pence, cents) as an integer. Never a decimal string. In |
lifetime_revenue_currencyrequired | string The merchant's currency, which |
lifetime_revenue_by_currencyrequired | array of Money Every currency the partner has sold in, the merchant's first (always present, at 0 if nothing was sold in it), then the largest. |
lifetime_commission_amountrequired | integer What the partner has earned, in the merchant's currency ( |
lifetime_commission_currencyrequired | string The merchant's currency, which |
lifetime_commission_by_currencyrequired | array of Money Every currency the partner has earned in, the merchant's first (always present, at 0 if nothing was earned in it), then the largest. |
rolesrequired | array of PartnerRole Empty rather than absent for a partner with none. |
tagsrequired | array of string |
first_click_atrequired | string (date-time) or null |
first_conversion_atrequired | string (date-time) or null |
last_activity_atrequired | string (date-time) or null |
approved_atrequired | string (date-time) or null |
forgotten_atrequired | string (date-time) or null When this record was erased, or null. Published because every other field on a forgotten partner is blanked, so a client left to infer it would be inferring from an absence, and a server syncing records needs to read this person asked to be forgotten rather than this person is called something odd now. |
created_atrequired | string (date-time) or null |
updated_atrequired | string (date-time) or null |
ServerPayout
A payout. Read only, and Refficks moves no money: status: paid means the merchant recorded that they sent it.
payment_details is not here and never will be. Payout details are encrypted at rest and the stored value is never returned to anybody. payment_hint is the mask, and is all this surface says about where money went.
| Field | What it is |
|---|---|
objectrequired | "payout" |
idrequired | Ulid |
partner_idrequired | Ulid |
statusrequired | PayoutStatus |
currencyrequired | string |
amountrequired | integer Minor units. |
entries_countrequired | integer |
payment_methodrequired | string or null |
payment_hintrequired | string or null The masked account: enough to recognise it on a statement, useless to anybody who obtains this payload. The real value leaves Refficks through the audited bank export alone. |
referencerequired | string or null |
void_reasonrequired | string or null Why the merchant called this payout off, in their own words. Readable here because the caller on this surface is the merchant. It is merchant-private: the partner it is about never receives it, on this surface or any other. Earlier versions of the API called it |
external_payout_idrequired | string or null The merchant's note of a transfer they made elsewhere. Refficks did not put it there. |
period_startrequired | string (date) or null |
period_endrequired | string (date) or null |
approved_atrequired | string (date-time) or null |
paid_atrequired | string (date-time) or null |
created_atrequired | string (date-time) or null |
updated_atrequired | string (date-time) or null |
ServerProgram
A programme as the management API publishes one. Every property is always present; absent data is null.
| Field | What it is |
|---|---|
objectrequired | "program" |
idrequired | Ulid |
modulerequired | ProgramModule |
namerequired | string |
slugrequired | string The last part of this programme's public address. |
descriptionrequired | string or null |
statusrequired | ProgramStatus |
default_currencyrequired | string |
attribution_window_daysrequired | integer How long a click keeps earning, what other platforms call the cookie duration. Captured at click time, so changing it never re-decides a conversion that already happened. |
auto_approve_partnersrequired | boolean |
terms_urlrequired | string (uri) or null |
default_destination_urlrequired | string (uri) or null Where links under this programme land when the link does not say. Without it, every link you mint must carry its own. |
created_atrequired | string (date-time) or null |
updated_atrequired | string (date-time) or null |
ServerProgramMembership
One partner's place in one programme: where the terms live. custom_commission_plan_id is readable and never writable.
| Field | What it is |
|---|---|
objectrequired | "program_membership" |
idrequired | Ulid |
program_idrequired | Ulid |
partner_idrequired | Ulid |
statusrequired | ProgramPartnerStatus |
tierrequired | string or null |
custom_commission_plan_idrequired | Ulid or null A plan of this partner's own that replaced every rule, from before a partner could have a figure per rule. Saving figures per rule on the dashboard retires it. What it pays belongs to the plan. |
own_ratesrequired | array of ServerOwnRate This partner's own figures on the programme's rules, in force. Read only: a figure is set on the partner's card in the dashboard. |
joined_atrequired | string (date-time) or null |
approved_atrequired | string (date-time) or null |
created_atrequired | string (date-time) or null |
updated_atrequired | string (date-time) or null |
ServerTrackingLink
A partner's link. url and destination_url are derived, not stored: a merchant who changes their link base expects every existing link to move.
| Field | What it is |
|---|---|
objectrequired | "tracking_link" |
idrequired | Ulid |
program_idrequired | Ulid |
partner_idrequired | Ulid |
coderequired | string Printed wherever the partner shared it, and therefore never changeable. |
namerequired | string or null |
urlrequired | string (uri) The form a partner shares. |
destination_urlrequired | string (uri) Where a click lands. |
attribution_window_daysrequired | integer |
attribution_window_sourcerequired | one of "link", "program" Which setting decided the window. The number alone cannot be acted on: reading 30 does not say whether editing the programme moves it. |
clicks_countrequired | integer |
statusrequired | TrackingStatus |
created_atrequired | string (date-time) or null |
updated_atrequired | string (date-time) or null |