# Affiliate Partners

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

The four endpoints that see, search, switch and remove the partners in the program.

## Overview

The affiliate program is where a client earns commission on the customers their own link brings in. This article manages the **people** in that program: who is there, who is on and who goes.

Every record carries **two numbers**. `id` belongs to the partner record and `owner_id` to the client behind it. The assignment endpoints speak the client number, so mixing the two makes a quiet wrong assignment.

The search endpoint sits here because it feeds the assignment screens: an interface that does not know the number types a name first, then hands the number it gets to the assignment.

## Reference

### Listing the Partners

get/api/v1/admin/affiliates

`Affiliates/GetAffiliates` admin

Returns the partners in the program with their earnings and referral totals.

Query 4

pageintWhich page.

limitintRecords per page. 100 at the most.

searchstringSearches the name, company, e-mail, partner id and client id.

statusstringThe status filter: `active` or `inactive`.

Response fields data[] — 13 + meta — 4

idintThe partner record id.

owner_idintThe client behind the partner. This is the number assignments use.

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.

disabledintWhether it is off. 0 means on and 1 means off.

balancestringThe earnings waiting to be paid. Text with four decimals.

currencyintThe currency id of the earnings.

referralsintHow many clients they referred.

hitsintHow many clicks their link took.

total_paidstringWhat has been paid out so far. It counts completed requests alone.

datestringWhen they joined the program.

totalintHow many partners 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 JavaScript PHP (HTTP) PHP (Internal)

```bash
curl 'https://panel.example.com/api/v1/admin/affiliates?status=active&limit=50' \
  -H "Authorization: Bearer $API_KEY"
```

```javascript
const res = await fetch('https://panel.example.com/api/v1/admin/affiliates?status=active', {
  headers: { Authorization: `Bearer ${apiKey}` },
});

const { data } = await res.json();
const owing = data.filter((a) => Number(a.balance) > 0);
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/affiliates?status=active');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
// id belongs to the PARTNER and owner_id to the CLIENT behind it; assignments speak owner_id.
$rows = Api::Affiliates()->GetAffiliates([], ['status' => 'active'])['data'];
$byClient = array_column($rows, 'balance', 'owner_id');
```

### Searching Partners, Clients and Services

get/api/v1/admin/affiliates/select

`Affiliates/SelectForAffiliate` admin 10 results at most

The search behind the assignment screens; you type a name instead of an id.

Query 2

typestringWhat to look for: `affiliate`, `client` or `service`. It looks for a partner by default.

qstringThe search text. It is taken under the name `search` as well.

Response fields data — 2

typestringThe kind searched. The same one you sent.

resultsobject[] results[]What was found.

idintThe id of the record found.

textstringThe label to show. A service gets its id and name, a person their name and company.

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/affiliates/select?type=client&q=jane' \
  -H "Authorization: Bearer $API_KEY"
```

```javascript
const url = new URL('https://panel.example.com/api/v1/admin/affiliates/select');
url.searchParams.set('type', 'client');
url.searchParams.set('q', term);

const res  = await fetch(url, { headers: { Authorization: `Bearer ${apiKey}` } });
const body = await res.json();
```

```php
$qs = http_build_query(['type' => 'client', 'q' => $term]);
$ch = curl_init('https://panel.example.com/api/v1/admin/affiliates/select?' . $qs);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
// It returns 10 results at most: this is a search box and not a listing.
$hits = Api::Affiliates()->SelectForAffiliate([], ['type' => 'client', 'q' => $term])['data'];
$exact = count($hits['results']) === 1 ? $hits['results'][0]['id'] : 0;
```

### Turning a Partner On and Off

put/api/v1/admin/affiliates/{aid}/status

`Affiliates/SetAffiliateStatus` admin

Turns a partner on or takes them out of the program.

Body 1

enabledboolreqWhether the partner is on. It becomes the opposite-named field on the record.

Response fields data — 2

idintThe partner id.

enabledboolWhere it now stands.

Errors 2

not_found404No such partner.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl -X PUT 'https://panel.example.com/api/v1/admin/affiliates/7/status' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"enabled":false}'
```

```javascript
const res = await fetch(`https://panel.example.com/api/v1/admin/affiliates/${aid}/status`, {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ enabled: false }),
});

const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/affiliates/' . $aid . '/status');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'PUT',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(['enabled' => false]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
// Turning a partner off DOES NOT wipe the earnings: the balance stays and payouts can still be asked for.
Api::Affiliates()->SetAffiliateStatus(['aid' => $aid, 'enabled' => false]);
```

### Removing a Partner

delete/api/v1/admin/affiliates/{aid}

`Affiliates/DeleteAffiliate` admin cannot be undone

Removes a partner along with every record tied to them.

Response fields data — 2

deletedboolWhether the delete ran.

idintThe id of the partner removed.

Errors 2

not_found404No such partner.

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/affiliates/7' \
  -H "Authorization: Bearer $API_KEY"
```

```javascript
const res = await fetch(`https://panel.example.com/api/v1/admin/affiliates/${aid}`, {
  method: 'DELETE',
  headers: { Authorization: `Bearer ${apiKey}` },
});

const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/affiliates/' . $aid);
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);
```

```php
// The panel asks for an admin password here while the API needs the scope alone. Consider turning them off first.
Api::Affiliates()->SetAffiliateStatus(['aid' => $aid, 'enabled' => false]);
// Api::Affiliates()->DeleteAffiliate(['aid' => $aid]);   // the earnings history goes as well
```

## Pitfalls

> **Two numbers: the partner id and the client id**
> 
> In the listing `id` is the partner record and `owner_id` the client behind it. The link kept on the client record also holds the **client number** rather than the partner one. Keep the two apart, since the assignment and status endpoints want different numbers.

> **Being off is spoken with two opposite words**
> 
> The listing gives a `disabled` field where **0 means on**. The status endpoint takes `enabled` where **true means on**. They are opposite names for one thing, and copying one into the other flips the state.

> **Removing takes the earnings history too**
> 
> Removing a partner also takes the commission entries, the payout requests, the clicks, the history and the referral records, while the linked clients lose their link. The panel asks for an admin password at this step and the API settles for the scope. Turn a partner off rather than remove them when you mean to part ways.

> **The search endpoint gives ten results at most**
> 
> The search endpoint is a search box and not a listing: it returns ten results at most no matter how many match, and there is no paging. Resting bulk work on it drops everything past the tenth without a word. Use the listing endpoint for the full set.

> **The paid total counts completed requests alone**
> 
> The `total_paid` field is the sum of completed payout requests. A waiting or in-flight request does not enter that number, and it is not taken out of `balance` either. Do not answer "what do we owe" by adding the two figures.

## Related Articles

- [Affiliate Assignments](https://dev.wisecp.com/en/affiliate-assignments)
- [Affiliate Payout Requests](https://dev.wisecp.com/en/affiliate-payout-requests)
- [Affiliate Program Settings](https://dev.wisecp.com/en/affiliate-program-settings)
