Affiliate Payout Requests

8 Aufrufe Markdown

The three endpoints that see and settle the payout requests partners open.

Overview

A partner cannot take the commission they earn straight away; they open a payout request and the team approves it. This article covers the three endpoints that see and settle those requests.

A request sits in one of five states: waiting, in process, completed, refused or cancelled. Only completed is the moment the money truly leaves, and it comes off the partner's balance.

What happens to the balance matters here: an approval takes the money down, a removal gives it back, and a refusal leaves the balance alone. Reading the three as one shows the partner a wrong figure.

Reference

Listing the Payout Requests

get/api/v1/admin/affiliates/withdrawals
Affiliates/GetWithdrawals admin

Returns the payout requests the partners opened.

Query 4
pageintWhich page.
limitintRecords per page. 100 at the most.
searchstringSearches the name, company, e-mail, payout method and request id.
statusstringThe status filter: awaiting, process, completed, rejected or cancelled.
Response fields data[] — 15 + meta — 4
idintThe request id.
affiliate_idintThe partner record that opened it.
owner_idintThe client behind the partner.
user_idintThe same client id. A second name coming from the query join.
full_namestringThe client's name.
company_namestringThe company name.
emailstringThe e-mail address.
amountstringThe amount asked for. Text with four decimals.
currencyintThe currency id of the amount.
gatewaystringThe payout method the partner picked.
gateway_infostringThe detail for that method. An account number or e-mail.
statusstringWhere the request stands.
status_msgstringThe note written on the status.
ctimestringWhen the request was opened.
updated_atstringWhen it last changed.
totalintHow many requests there are. It comes back under meta.
pageintThe page you are on.
limitintThe page size.
next_pageintThe next page. Zero on the last one.
Errors 1
insufficient_scope403The key lacks the required scope.
Request
curl 'https://panel.example.com/api/v1/admin/affiliates/withdrawals?status=awaiting' \
  -H "Authorization: Bearer $API_KEY"
const res = await fetch('https://panel.example.com/api/v1/admin/affiliates/withdrawals?status=awaiting', {
  headers: { Authorization: `Bearer ${apiKey}` },
});

const { data, meta } = await res.json();
const owed = data.reduce((s, w) => s + Number(w.amount), 0);
$ch = curl_init('https://panel.example.com/api/v1/admin/affiliates/withdrawals?status=awaiting');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// The amounts sit in EACH REQUEST's own currency; convert before adding them up.
$rows = Api::Affiliates()->GetWithdrawals([], ['status' => 'awaiting'])['data'];
$byCurrency = [];
foreach ($rows as $w) $byCurrency[$w['currency']] = ($byCurrency[$w['currency']] ?? 0) + (float) $w['amount'];

Handling Requests in Bulk

post/api/v1/admin/affiliates/withdrawals/bulk
Affiliates/BulkWithdrawals admin touches the balance

Approves, refuses or removes several payout requests.

Body 2
actionstringreqWhat to do: approve, reject or delete.
idsint[]reqThe request ids to work on. An id that is not found gets skipped without a word.
Response fields data — 2
actionstringThe job applied.
processedint[]The ids you sent. Not the ones that truly changed.
Errors 3
action_invalid422The job name is none of the three values.
ids_required422No request id was given.
insufficient_scope403The key lacks the required scope.
Request
curl -X POST 'https://panel.example.com/api/v1/admin/affiliates/withdrawals/bulk' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"action":"approve","ids":[3,5]}'
const res = await fetch('https://panel.example.com/api/v1/admin/affiliates/withdrawals/bulk', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ action: 'approve', ids: [3, 5] }),
});

const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/affiliates/withdrawals/bulk');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(['action' => 'approve', 'ids' => [3, 5]]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// APPROVE takes it off the balance and REJECT DOES NOT give it back; delete is the one job that refunds.
Api::Affiliates()->BulkWithdrawals(['action' => 'approve', 'ids' => [3, 5]]);
// approved by mistake: delete rather than reject
Api::Affiliates()->BulkWithdrawals(['action' => 'delete', 'ids' => [3]]);

Removing One Request

delete/api/v1/admin/affiliates/withdrawals/{wid}
Affiliates/DeleteWithdrawal admin

Removes one payout request and gives the amount back where needed.

Response fields data — 2
deletedboolWhether the delete ran.
idintThe id of the request removed.
Errors 2
not_found404No such request.
insufficient_scope403The key lacks the required scope.
Request
curl -X DELETE 'https://panel.example.com/api/v1/admin/affiliates/withdrawals/3' \
  -H "Authorization: Bearer $API_KEY"
const res = await fetch(`https://panel.example.com/api/v1/admin/affiliates/withdrawals/${wid}`, {
  method: 'DELETE',
  headers: { Authorization: `Bearer ${apiKey}` },
});

const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/affiliates/withdrawals/' . $wid);
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);
// The one difference from a bulk delete: a missing id gives 404 here and is skipped in bulk.
Api::Affiliates()->DeleteWithdrawal(['wid' => $wid]);

Pitfalls

A refusal does not give the balance back

An approval takes the amount off the partner's balance. A refusal writes the status alone and does not put the amount back, so refusing a request you approved leaves the money short on that balance for good. The way back from a wrong approval is removal and not refusal.

Approve, refuse, approve again takes it twice

An approval takes from the balance only while the request is not already completed. Refusing an approved request and approving it again drops the state out of completed, so it takes a second time and the partner loses twice for one payout. Check the balance by hand after a round like that.

The list that comes back does not say what was handled

The processed field is the same set of ids you sent. A request that is not found gets skipped without a word, while its id still shows in that list. Read the statuses back from the listing endpoint to see that bulk work landed.

The balance never goes below zero

Every job that takes from the balance stops at zero. Approving a request larger than the balance leaves it at zero and the difference disappears with no error. Compare the request amount against the partner's balance before approving.

Two ways to remove, one difference

Removing one request and removing many do the same job, and both give the amount back on a completed request. The one difference is a missing id: the single endpoint answers 404 while the bulk one skips quietly. The single endpoint is safer for an id you are unsure of.

War das hilfreich?

Vielen Dank für Ihre Rückmeldung!

Brauchen Sie weitere Hilfe?

Unser Support-Team ist rund um die Uhr für Sie da, wenn Sie oben nicht fündig werden.