# Affiliate Assignments

https://dev.wisecp.com/es/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

get/api/v1/admin/affiliates/assigned-clients

`Affiliates/GetAssignedClients` admin

Returns the clients linked to a partner.

Query 3

pageintWhich page.

limitintRecords per page. 100 at the most.

searchstringSearches the client and partner name along with the company.

Response fields data[] — 8 + meta — 4

idintThe client id.

full_namestringThe client's name.

company_namestringThe client's company.

emailstringThe client's e-mail.

aff_idintThe **client** number of the partner they are linked to. Not the partner record id.

aff_namestringThe partner's name.

aff_companystringThe partner's company.

aff_user_idintThe partner's client id.

totalintHow many linked clients 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/assigned-clients?search=jane' \
  -H "Authorization: Bearer $API_KEY"
```

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

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

```php
// 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

post/api/v1/admin/affiliates/assigned-clients

`Affiliates/AssignClient` admin

Marks a client as a partner's referral.

Body 2

affiliate_idintreqThe partner record id.

client_idintreqThe id of the client to link.

Response fields data — 3

assignedboolWhether the link was made.

affiliate_idintThe partner id.

client_idintThe client id.

Errors 4

missing_params422The partner or client id is missing.

assign_self422A client cannot be linked to their own partnership.

not_found404No such partner or client.

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/affiliates/assigned-clients' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"affiliate_id":7,"client_id":88}'
```

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

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

```php
// 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

delete/api/v1/admin/affiliates/assigned-clients

`Affiliates/UnassignClients` admin

Takes the partner link off one client or more.

Body 1

idsint[]reqThe **client** ids. Not assignment ids.

Response fields data — 1

unassignedint[]The client ids you sent.

Errors 2

ids_required422No client id was given.

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/assigned-clients' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"ids":[88,90]}'
```

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

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

```php
// 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

get/api/v1/admin/affiliates/assigned-services

`Affiliates/GetAssignedServices` admin

Returns the service records earning partners their commission.

Query 4

pageintWhich page.

limitintRecords per page. 100 at the most.

searchstringSearches the client, partner, service name and record id.

statusstringThe record status filter.

Response fields data[] — 15 + meta — 4

idintThe commission record id. The removal endpoint wants this number.

affiliate_idintThe partner record id.

service_idintThe service id.

service_namestringThe service name.

user_idintThe id of the client owning the service.

full_namestringThe client's name.

company_namestringThe client's company.

amountstringThe service amount. What the commission is worked out from.

currencyintThe currency id of the amount.

commissionstringThe commission written to the partner.

statusstringWhere the record stands. A completed one already went to the balance.

aff_namestringThe partner's name.

aff_companystringThe partner's company.

aff_user_idintThe partner's client id.

ctimestringWhen the record was opened.

totalintHow many records 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/assigned-services?limit=50' \
  -H "Authorization: Bearer $API_KEY"
```

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

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

```php
// 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

post/api/v1/admin/affiliates/assigned-services

`Affiliates/AssignService` admin five conditions

Links a service to a partner and opens the commission record.

Body 2

affiliate_idintreqThe partner record id.

service_idintreqThe id of the service to link.

Response fields data — 3

assignedboolWhether the link was made.

affiliate_idintThe partner id.

service_idintThe service id.

Errors 8

missing_params422The partner or service id is missing.

system_disabled422The affiliate program is off.

type_unsupported422The service type does not take commission. Hosting, server, software and special types pass.

product_disabled422The affiliate program is off for this product.

affiliate_disabled422The partner is off.

already_assigned422The service is linked to another partner.

not_found404No such partner or service.

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/affiliates/assigned-services' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"affiliate_id":7,"service_id":305}'
```

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

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

```php
// 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

delete/api/v1/admin/affiliates/assigned-services/{tid}

`Affiliates/UnassignService` admin touches the balance

Removes the commission record and takes the commission back where needed.

Response fields data — 2

unassignedboolWhether the removal ran.

idintThe id of the record removed.

Errors 2

not_found404No such commission record.

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

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

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

```php
// On a completed record the commission comes OFF the balance; the OPPOSITE way to a payout removal.
Api::Affiliates()->UnassignService(['tid' => $recordId]);
```

## Pitfalls

> **The two removal endpoints want two different numbers**
> 
> 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.

> **Removing a client link checks nothing**
> 
> 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.

> **A link silently takes over an existing one**
> 
> 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 commission record takes from the balance**
> 
> 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 link field holds a client id and not a partner id**
> 
> 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.

> **The service type and product setting form a quiet gate**
> 
> 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

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