# Affiliate

https://dev.wisecp.com/es/affiliate-endpoints

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

get/api/v1/admin/clients/{id}/affiliate

`Clients/GetClientAffiliate` admin

Returns the client's affiliate status, commission settings and balance.

Response fields data — 8

is_affiliateboolWhether the client is an affiliate.

activated_atdatetimeWhen the partnership was opened.

disabledboolWhether the partnership is switched off.

disabled_reasonstringWhy it was switched off.

commission_valuefloatCommission rate as a percentage. Between 0 and 100.

commission_periodstring`lifetime` pays on every renewal, `onetime` only on the first sale. An empty value uses the default.

balancefloatThe partner's earnings balance.

currency_idintCurrency id of the balance.

Errors 2

not_found404No such client.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl 'https://panel.example.com/api/v1/admin/clients/42/affiliate' \
  -H "Authorization: Bearer $API_KEY"
```

```javascript
const res  = await fetch('https://panel.example.com/api/v1/admin/clients/42/affiliate', {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();
```

```php
$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);
```

```php
$response = Api::Clients()->GetClientAffiliate(['id' => 42]);

if (!($response['data']['is_affiliate'] ?? false)) {
    return;
}
```

### Opening the Partnership

post/api/v1/admin/clients/{id}/affiliate

`Clients/ActivateClientAffiliate` admin

Makes the client an affiliate. On a client who already is one, it returns an error.

Body 3

commission_valuenumberCommission rate. Clamped to 0-100; a value outside that is not refused, it is trimmed.

commission_periodstring`lifetime` or `onetime`. Anything else becomes empty.

currency_idintBalance currency. List: `reference/currencies`.

Response fields data

dataobjectThe partnership opened, returned with `201`. Same shape as the status endpoint.

Errors 4

not_found404No such client.

already_affiliate422The client is already an affiliate.

activate_failed500The partnership could not be opened.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
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}'
```

```javascript
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();
```

```php
$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);
```

```php
$response = Api::Clients()->ActivateClientAffiliate([
    'id'                => 42,
    'commission_value'  => 10,
    'commission_period' => 'lifetime',
    'currency_id'       => 1,
]);
```

### Updating the Partnership

patch/api/v1/admin/clients/{id}/affiliate

`Clients/UpdateClientAffiliate` admin blocking lives here

Changes the commission, the balance and the partner's state. Blocking goes through here too.

Body 7

commission_valuenumberCommission rate; clamped to 0-100.

commission_periodstring`lifetime` ya da `onetime`.

currency_idintBalance currency.

balancenumberThe partner's balance. A negative value is pulled up to zero.

disabledboolSwitches the partnership off or back on.

disabled_reasonstringWhy it was switched off. Only written while `disabled` is on.

block_partnerboolBlocks the partner **and cancels the waiting withdrawal requests**.

Response fields data

dataobjectThe partnership as it now stands. Same shape as the status endpoint.

Errors 3

not_found404No such client.

not_affiliate422The client is not an affiliate.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
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}'
```

```javascript
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();
```

```php
$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);
```

```php
// Blocking also cancels the waiting withdrawal requests.
$response = Api::Clients()->UpdateClientAffiliate([
    'id'            => 42,
    'block_partner' => true,
    'block_reason'  => 'Fake referrals',
]);
```

### Running a Fraud Check

post/api/v1/admin/clients/{id}/affiliate/fraud-check

`Clients/CheckClientAffiliateFraud` admin

Scans the partner's referrals and returns the suspicious patterns.

Body —

——No body is needed. The scan always covers the partner's whole referral history and cannot be narrowed.

Response fields data — 3

flaggedboolWhether the partner was flagged.

self_referralsintHow many referrals the partner made to themselves.

shared_ip_referralsarrayReferrals coming from the same IP as the partner.

Errors 3

not_found404No such client.

not_affiliate422The client is not an affiliate.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl -X POST 'https://panel.example.com/api/v1/admin/clients/42/affiliate/fraud-check' \
  -H "Authorization: Bearer $API_KEY"
```

```javascript
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();
```

```php
$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);
```

```php
$response = Api::Clients()->CheckClientAffiliateFraud(['id' => 42]);

// The scan only reports; blocking is your decision and your call.
if ($response['data']['flagged'] ?? false) {
    $selfReferrals = $response['data']['self_referrals'];
}
```

### Listing Withdrawal Requests

get/api/v1/admin/clients/{id}/affiliate/withdrawals

`Clients/GetClientAffiliateWithdrawals` admin

Returns the requests the partner opened to withdraw their earnings.

Response fields data[] — 6

idintId of the withdrawal request.

amountfloatThe amount asked for.

gatewaystringThe method the payment goes out through.

statusstring`awaiting`, `process`, `completed`, `rejected` or `cancelled`.

status_msgstringA note on the status.

created_atdatetimeWhen the request was opened.

Errors 3

not_found404No such client.

not_affiliate422The client is not an affiliate.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl 'https://panel.example.com/api/v1/admin/clients/42/affiliate/withdrawals' \
  -H "Authorization: Bearer $API_KEY"
```

```javascript
const res  = await fetch('https://panel.example.com/api/v1/admin/clients/42/affiliate/withdrawals', {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();
```

```php
$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);
```

```php
$response = Api::Clients()->GetClientAffiliateWithdrawals(['id' => 42]);
```

### Updating a Withdrawal Request

patch/api/v1/admin/clients/{id}/affiliate/withdrawals/{wid}

`Clients/UpdateClientAffiliateWithdrawal` admin a receipt can be attached

Changes the request status. If you made the payment, the receipt goes in the same request.

Body 4

statusstringrequiredThe new status. Older names are accepted: `pending` → `awaiting`, `inprocess` → `process`, `paid` → `completed`.

status_msgstringA message for the partner.

receiptstring | objectThe payment receipt. Accepted only on the move to `completed`. A base64 data URI, `{filename, content}` or `{url}`. Allowed: images and PDF.

remove_receiptboolRemoves the receipt already attached.

Response fields data

dataobjectThe request as it now stands. Same shape as an item in the request list.

Errors 4

not_found404No such client or withdrawal request.

status_required422`status` was empty.

file_invalid422The receipt could not be read or stored.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
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"}}'
```

```javascript
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();
```

```php
$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);
```

```php
$response = Api::Clients()->UpdateClientAffiliateWithdrawal([
    'id'      => 42,
    'wid'     => 5,
    'status'  => 'completed',
    'receipt' => ['url' => 'https://example.com/receipt.pdf'],
]);
```

### Listing Canned Texts

get/api/v1/admin/clients/affiliate/templates

`Clients/GetAffiliateTemplates` admin

Returns the canned texts used in affiliate work: deactivation reasons, withdrawal notes, block reasons.

Response fields data — 3

deactivate_reasonsstring[]Reasons for closing a partnership.

withdrawal_notesstring[]Notes put on a withdrawal request.

block_reasonsstring[]Reasons for blocking.

Errors 1

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl 'https://panel.example.com/api/v1/admin/clients/affiliate/templates' \
  -H "Authorization: Bearer $API_KEY"
```

```javascript
const res  = await fetch('https://panel.example.com/api/v1/admin/clients/affiliate/templates', {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();
```

```php
$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);
```

```php
$response = Api::Clients()->GetAffiliateTemplates();
```

### Adding a Canned Text

post/api/v1/admin/clients/affiliate/templates

`Clients/AddAffiliateTemplate` admin

Adds a text to the type you choose.

Body 2

typestringrequiredMetnin türü: `deactivate_reasons`, `withdrawal_notes` or `block_reasons`.

valuestringrequiredThe text to add.

Response fields data — 2

typestringThe type the text went into.

itemsstring[]That type's list as it now stands.

Errors 3

type_invalid422The type is not one of the three values.

value_required422`value` was empty.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
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"}'
```

```javascript
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();
```

```php
$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);
```

```php
$response = Api::Clients()->AddAffiliateTemplate([
    'type'  => 'block_reasons',
    'value' => 'Fake referrals detected',
]);
```

### Deleting a Canned Text

delete/api/v1/admin/clients/affiliate/templates

`Clients/DeleteAffiliateTemplate` admin deleted by text

Removes a text from the list. You send the text itself, not an id.

Body 2

typestringrequiredMetnin türü: `deactivate_reasons`, `withdrawal_notes` or `block_reasons`.

valuestringrequiredThe text to remove. It has to match the stored one exactly.

Response fields data — 2

typestringThe type the text came out of.

itemsstring[]That type's list as it now stands.

Errors 3

type_invalid422The type is not one of the three values.

value_required422`value` was empty.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
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"}'
```

```javascript
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();
```

```php
$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);
```

```php
$response = Api::Clients()->DeleteAffiliateTemplate([
    'type'  => 'block_reasons',
    'value' => 'Fake referrals detected',
]);
```

## Pitfalls

> **Values are trimmed, not refused**
> 
> 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.

> **Blocking cancels waiting payouts**
> 
> `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 fraud scan makes no decision**
> 
> 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

- [Client Endpoints](https://dev.wisecp.com/en/client-endpoints)
- [Blacklist and Duplicates](https://dev.wisecp.com/en/blacklist-and-duplicates)
