Affiliate Assignments
The six endpoints that link, list and unlink clients and services against a partner.
Overview
A partner earns in two ways. A client link says "they brought this customer in", while a service link writes commission on one particular sale.
The two live in different places. A client link is a field on the client record, and a service link opens a commission record of its own. That is why the two removal endpoints speak different numbers.
Linking a service looks for five conditions. The program has to be on and the service type suitable. The product must stay open to commission, the partner switched on, and the service free of another partner.
Reference
Listing the Linked Clients
Returns the clients linked to a partner.
curl 'https://panel.example.com/api/v1/admin/affiliates/assigned-clients?search=jane' \
-H "Authorization: Bearer $API_KEY"const res = await fetch('https://panel.example.com/api/v1/admin/affiliates/assigned-clients', {
headers: { Authorization: `Bearer ${apiKey}` },
});
const { data } = await res.json();
const perPartner = Object.groupBy(data, (c) => c.aff_user_id);$ch = curl_init('https://panel.example.com/api/v1/admin/affiliates/assigned-clients');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// aff_id is the partner's CLIENT number; do not try to match it with the partner record id.
$rows = Api::Affiliates()->GetAssignedClients()['data'];
$mine = array_filter($rows, fn ($c) => (int) $c['aff_user_id'] === $partnerClientId);Linking a Client to a Partner
Marks a client as a partner's referral.
curl -X POST 'https://panel.example.com/api/v1/admin/affiliates/assigned-clients' \
-H "Authorization: Bearer $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"affiliate_id":7,"client_id":88}'const res = await fetch('https://panel.example.com/api/v1/admin/affiliates/assigned-clients', {
method: 'POST',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ affiliate_id: 7, client_id: 88 }),
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/affiliates/assigned-clients');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode(['affiliate_id' => 7, 'client_id' => 88]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// A client tied to another partner is taken over SILENTLY; the first partner loses the referral.
$rows = Api::Affiliates()->GetAssignedClients()['data'];
$owned = array_column($rows, 'aff_user_id', 'id');
if (! isset($owned[$clientId])) Api::Affiliates()->AssignClient(['affiliate_id' => $aid, 'client_id' => $clientId]);Removing a Client Link
Takes the partner link off one client or more.
curl -X DELETE 'https://panel.example.com/api/v1/admin/affiliates/assigned-clients' \
-H "Authorization: Bearer $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"ids":[88,90]}'const res = await fetch('https://panel.example.com/api/v1/admin/affiliates/assigned-clients', {
method: 'DELETE',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ ids: [88, 90] }),
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/affiliates/assigned-clients');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode(['ids' => [88, 90]]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// There is NO check: the link goes off every client you send, and unlinked ones fill the answer too.
Api::Affiliates()->UnassignClients(['ids' => [88, 90]]);Listing the Linked Services
Returns the service records earning partners their commission.
curl 'https://panel.example.com/api/v1/admin/affiliates/assigned-services?limit=50' \
-H "Authorization: Bearer $API_KEY"const res = await fetch('https://panel.example.com/api/v1/admin/affiliates/assigned-services', {
headers: { Authorization: `Bearer ${apiKey}` },
});
const { data } = await res.json();
const earned = data.reduce((s, t) => s + Number(t.commission), 0);$ch = curl_init('https://panel.example.com/api/v1/admin/affiliates/assigned-services');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// The removal endpoint wants the RECORD id from here rather than the SERVICE id.
$rows = Api::Affiliates()->GetAssignedServices()['data'];
$recordId = array_column($rows, 'id', 'service_id')[$serviceId] ?? 0;Linking a Service to a Partner
Links a service to a partner and opens the commission record.
curl -X POST 'https://panel.example.com/api/v1/admin/affiliates/assigned-services' \
-H "Authorization: Bearer $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"affiliate_id":7,"service_id":305}'const res = await fetch('https://panel.example.com/api/v1/admin/affiliates/assigned-services', {
method: 'POST',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ affiliate_id: 7, service_id: 305 }),
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/affiliates/assigned-services');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode(['affiliate_id' => 7, 'service_id' => 305]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// Five conditions are checked at once; the two missed most are an off program and a service already linked.
try { Api::Affiliates()->AssignService(['affiliate_id' => $aid, 'service_id' => $sid]); }
catch (\Throwable $e) { $skipped[$sid] = $e->getMessage(); }Removing a Service Link
Removes the commission record and takes the commission back where needed.
curl -X DELETE 'https://panel.example.com/api/v1/admin/affiliates/assigned-services/12' \
-H "Authorization: Bearer $API_KEY"const res = await fetch(`https://panel.example.com/api/v1/admin/affiliates/assigned-services/${tid}`, {
method: 'DELETE',
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/affiliates/assigned-services/' . $tid);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// On a completed record the commission comes OFF the balance; the OPPOSITE way to a payout removal.
Api::Affiliates()->UnassignService(['tid' => $recordId]);Pitfalls
The endpoint removing a client link wants client ids in the body. The one removing a service link wants the commission record id in the address. Handing the second a service id either answers not found or removes the wrong record. Take the record id from the listing endpoint.
This endpoint takes the link off every client id you send. It never looks at whether the id was linked to a partner, nor whether that client exists. All of them count as removed in the answer. A wrong list quietly cuts other clients' links.
When a client is already linked to another partner the new link raises no error. It writes over the old one, and the first partner loses that referral. On the service side the same case is refused with already_assigned. Check the existing link from the listing endpoint before linking a client.
Removing a completed commission record takes the amount off the partner's balance. Remember that removing a payout request adds to it: the two removals work in opposite directions. The balance never goes below zero, so a difference that cannot be taken disappears without a word.
The aff_id in the listing is the client behind the partner and not the partner record id. The linking endpoint, meanwhile, wants the partner record id in the body. Passing a number read from one listing straight into the other assigns to a different partner.
Commission is written on hosting, server, software and special services alone, and other types such as a domain get type_unsupported. The product's own setting can close commission as well. Gather those two cases apart during bulk linking work.
Related Articles
Thanks for your feedback!
Our support team is here around the clock for anything you can't find above.