Affiliate
The nine endpoints that open an affiliate partnership, set the commission, run the payout and scan for suspicious referrals.
Overview
In an affiliate partnership a client earns commission on every sale they bring. These endpoints open the partnership, set the commission rule, run the payout and scan for suspicious referrals.
Commission has two periods: lifetime pays on every renewal the referred client makes, onetime only on the first sale. The choice is per partner.
Reference
Reading the Affiliate Status
Returns the client's affiliate status, commission settings and balance.
lifetime pays on every renewal, onetime only on the first sale. An empty value uses the default.curl 'https://panel.example.com/api/v1/admin/clients/42/affiliate' \
-H "Authorization: Bearer $API_KEY"const res = await fetch('https://panel.example.com/api/v1/admin/clients/42/affiliate', {
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/clients/42/affiliate');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);$response = Api::Clients()->GetClientAffiliate(['id' => 42]);
if (!($response['data']['is_affiliate'] ?? false)) {
return;
}Opening the Partnership
Makes the client an affiliate. On a client who already is one, it returns an error.
lifetime or onetime. Anything else becomes empty.reference/currencies.201. Same shape as the status endpoint.curl -X POST 'https://panel.example.com/api/v1/admin/clients/42/affiliate' \
-H "Authorization: Bearer $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"commission_value":10,"commission_period":"lifetime","currency_id":1}'const res = await fetch('https://panel.example.com/api/v1/admin/clients/42/affiliate', {
method: 'POST',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
commission_value: 10,
commission_period: 'lifetime',
currency_id: 1,
}),
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/clients/42/affiliate');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'commission_value' => 10,
'commission_period' => 'lifetime',
'currency_id' => 1,
]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);$response = Api::Clients()->ActivateClientAffiliate([
'id' => 42,
'commission_value' => 10,
'commission_period' => 'lifetime',
'currency_id' => 1,
]);Updating the Partnership
Changes the commission, the balance and the partner's state. Blocking goes through here too.
lifetime ya da onetime.disabled is on.curl -X PATCH 'https://panel.example.com/api/v1/admin/clients/42/affiliate' \
-H "Authorization: Bearer $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"commission_value":15}'const res = await fetch('https://panel.example.com/api/v1/admin/clients/42/affiliate', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ commission_value: 15 }),
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/clients/42/affiliate');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PATCH',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode(['commission_value' => 15]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// Blocking also cancels the waiting withdrawal requests.
$response = Api::Clients()->UpdateClientAffiliate([
'id' => 42,
'block_partner' => true,
'block_reason' => 'Fake referrals',
]);Running a Fraud Check
Compares the IP addresses the partner signed in from with the sign-in IPs of the clients they referred, and lists every referred client that shares one. Staff "log in as client" sessions are ignored. Read state first: no_referrals and no_logins mean there was nothing to compare, which is not a clean result.
match · clean · no_referrals · no_logins. The last two mean the partner has no referred clients, or no sign-in of their own to compare.true only when state is match.state is match.curl -X POST 'https://panel.example.com/api/v1/admin/clients/42/affiliate/fraud-check' \
-H "Authorization: Bearer $API_KEY"const res = await fetch('https://panel.example.com/api/v1/admin/clients/42/affiliate/fraud-check', {
method: 'POST',
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/clients/42/affiliate/fraud-check');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);$response = Api::Clients()->CheckClientAffiliateFraud(['id' => 42]);
// The scan only reports; blocking is your decision and your call.
if (($response['data']['state'] ?? '') === 'match') {
$sharedIps = $response['data']['matching_ips'];
}Listing Withdrawal Requests
Returns the requests the partner opened to withdraw their earnings.
awaiting, process, completed, rejected or cancelled.curl 'https://panel.example.com/api/v1/admin/clients/42/affiliate/withdrawals' \
-H "Authorization: Bearer $API_KEY"const res = await fetch('https://panel.example.com/api/v1/admin/clients/42/affiliate/withdrawals', {
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/clients/42/affiliate/withdrawals');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);$response = Api::Clients()->GetClientAffiliateWithdrawals(['id' => 42]);Updating a Withdrawal Request
Changes the request status. If you made the payment, the receipt goes in the same request.
pending → awaiting, inprocess → process, paid → completed.completed. A base64 data URI, {filename, content} or {url}. Allowed: images and PDF.status was empty.curl -X PATCH 'https://panel.example.com/api/v1/admin/clients/42/affiliate/withdrawals/5' \
-H "Authorization: Bearer $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"status":"completed","receipt":{"url":"https://example.com/receipt.pdf"}}'const res = await fetch('https://panel.example.com/api/v1/admin/clients/42/affiliate/withdrawals/5', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
status: 'completed',
receipt: { url: 'https://example.com/receipt.pdf' },
}),
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/clients/42/affiliate/withdrawals/5');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PATCH',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'status' => 'completed',
'receipt' => ['url' => 'https://example.com/receipt.pdf'],
]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);$response = Api::Clients()->UpdateClientAffiliateWithdrawal([
'id' => 42,
'wid' => 5,
'status' => 'completed',
'receipt' => ['url' => 'https://example.com/receipt.pdf'],
]);Listing Canned Texts
Returns the canned texts used in affiliate work: deactivation reasons, withdrawal notes, block reasons.
curl 'https://panel.example.com/api/v1/admin/clients/affiliate/templates' \
-H "Authorization: Bearer $API_KEY"const res = await fetch('https://panel.example.com/api/v1/admin/clients/affiliate/templates', {
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/clients/affiliate/templates');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);$response = Api::Clients()->GetAffiliateTemplates();Adding a Canned Text
Adds a text to the type you choose.
deactivate_reasons, withdrawal_notes or block_reasons.value was empty.curl -X POST 'https://panel.example.com/api/v1/admin/clients/affiliate/templates' \
-H "Authorization: Bearer $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"type":"block_reasons","value":"Fake referrals detected"}'const res = await fetch('https://panel.example.com/api/v1/admin/clients/affiliate/templates', {
method: 'POST',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ type: 'block_reasons', value: 'Fake referrals detected' }),
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/clients/affiliate/templates');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'type' => 'block_reasons',
'value' => 'Fake referrals detected',
]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);$response = Api::Clients()->AddAffiliateTemplate([
'type' => 'block_reasons',
'value' => 'Fake referrals detected',
]);Deleting a Canned Text
Removes a text from the list. You send the text itself, not an id.
deactivate_reasons, withdrawal_notes or block_reasons.value was empty.curl -X DELETE 'https://panel.example.com/api/v1/admin/clients/affiliate/templates' \
-H "Authorization: Bearer $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"type":"block_reasons","value":"Fake referrals detected"}'const res = await fetch('https://panel.example.com/api/v1/admin/clients/affiliate/templates', {
method: 'DELETE',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ type: 'block_reasons', value: 'Fake referrals detected' }),
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/clients/affiliate/templates');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'type' => 'block_reasons',
'value' => 'Fake referrals detected',
]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);$response = Api::Clients()->DeleteAffiliateTemplate([
'type' => 'block_reasons',
'value' => 'Fake referrals detected',
]);Pitfalls
The commission rate is clamped to 0-100, a negative balance is pulled up to zero, and an unrecognised commission period becomes empty. None of these raise an error; a wrong value is quietly stored as a corrected one. Read back after writing.
block_partner does not only stop the partner; it also cancels the waiting withdrawal requests. Look at the request list before blocking a partner who is about to be paid.
The scan only reports: how many self-referrals there are and which records came from the same IP. Blocking the partner is a separate request and the decision is yours.
Related Articles
شكرًا على ملاحظاتك!
فريق الدعم متاح على مدار الساعة لمساعدتك في كل ما لم تجده أعلاه.