Appearance
Affiliates
List Affiliates
Retrieve a paginated list of all affiliates for your business.
GET /v1/affiliates
- Required scope:
affiliates:read - Rate limit: 120 requests/minute
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | Page number |
per_page | integer | 25 | Results per page. Max 100 |
status | string | — | Filter by status: pending | active | suspended | terminated |
search | string | — | Search across name, email, and referral code |
sort | string | created_at | Sort field: created_at | referral_code | status | commission_rate |
direction | string | desc | Sort direction: asc | desc |
Example Request
bash
curl "https://heldsway.com/api/v1/affiliates?status=active&per_page=10&sort=created_at&direction=desc" \
-H "Authorization: Bearer <access_token>"Success Response — 200 OK
json
{
"success": true,
"message": "OK",
"data": {
"items": [
{
"id": 42,
"referral_code": "ABC12345",
"status": "active",
"commission_rate": "10.00",
"notes": null,
"approved_at": "2026-04-01T09:00:00.000000Z",
"suspended_at": null,
"terminated_at": null,
"created_at": "2026-03-15T14:22:00.000000Z",
"affiliate_user": {
"id": 7,
"name": "Jane Doe",
"email": "jane@example.com",
"phone": null
}
}
],
"meta": {
"current_page": 1,
"per_page": 10,
"total": 87,
"last_page": 9
}
}
}Get Affiliate
Retrieve a single affiliate by ID.
GET /v1/affiliates/{id}
- Required scope:
affiliates:read - Rate limit: 120 requests/minute
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | integer | Affiliate ID |
Example Request
bash
curl "https://heldsway.com/api/v1/affiliates/42" \
-H "Authorization: Bearer <access_token>"Success Response — 200 OK
json
{
"success": true,
"message": "OK",
"data": {
"id": 42,
"referral_code": "ABC12345",
"status": "active",
"commission_rate": "10.00",
"notes": "VIP partner",
"approved_at": "2026-04-01T09:00:00.000000Z",
"suspended_at": null,
"terminated_at": null,
"created_at": "2026-03-15T14:22:00.000000Z",
"affiliate_user": {
"id": 7,
"name": "Jane Doe",
"email": "jane@example.com",
"phone": "+14155552671"
},
"referral_links_count": 3
}
}Error Responses
| Status | Code | Description |
|---|---|---|
404 | NOT_FOUND | Affiliate does not exist for this business |
Create Affiliate
Create a new affiliate account directly. The affiliate is immediately set to active status — no approval step required. Use this when you are adding affiliates on their behalf.
If the email already exists as an affiliate user account (across any business), they will be linked to your business without changing their password. If no account exists, one is created with the provided credentials.
POST /v1/affiliates
- Required scope:
affiliates:write - Rate limit: 60 requests/minute
Request Body
| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
name | string | Yes | max 255 | Affiliate's full name |
email | string | Yes | valid email, max 255 | Affiliate's email address |
password | string | Yes | min 8, max 255 | Account password |
phone | string | No | max 30 | Phone number |
commission_rate | float | No | 0–100 | Override commission rate (%). Omit to use business default |
notes | string | No | max 1000 | Internal notes |
referral_code | string | No | alphanumeric, max 32, unique | Custom referral code. Auto-generated if omitted |
Example Request
bash
curl -X POST "https://heldsway.com/api/v1/affiliates" \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{
"name": "Jane Doe",
"email": "jane@example.com",
"password": "SecurePass123!",
"phone": "+14155552671",
"commission_rate": 12.5,
"notes": "Referred by our sales team",
"referral_code": "JANE2026"
}'Success Response — 201 Created
json
{
"success": true,
"message": "Created",
"data": {
"id": 42,
"referral_code": "JANE2026",
"status": "active",
"commission_rate": "12.50",
"notes": "Referred by our sales team",
"approved_at": "2026-04-13T10:00:00.000000Z",
"suspended_at": null,
"terminated_at": null,
"created_at": "2026-04-13T10:00:00.000000Z",
"affiliate_user": {
"id": 7,
"name": "Jane Doe",
"email": "jane@example.com",
"phone": "+14155552671"
}
}
}Error Responses
| Status | Code | Description |
|---|---|---|
409 | AFFILIATE_EXISTS | This email is already an affiliate of your business |
422 | VALIDATION_ERROR | Missing or invalid fields |
Affiliate Self-Registration
Allow an individual to register themselves as an affiliate for your business. This endpoint is intended for use in your own frontend — your backend calls our API with your access token, passing the user's details.
Prerequisite: The business setting
allow_self_registrationmust be enabled. If it is off, this endpoint returns403. This setting is configured in your business dashboard under Affiliate Program → Settings.
Affiliates created via this endpoint start with pending status and must be approved by you before they can earn commissions.
POST /v1/affiliates/register
- Required scope:
affiliates:write - Rate limit: 30 requests/minute
Request Body
| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
name | string | Yes | max 255 | Applicant's full name |
email | string | Yes | valid email, max 255 | Applicant's email |
password | string | Yes | min 8, max 255 | Account password they will use to log in |
phone | string | No | max 30 | Phone number |
Example Request
bash
curl -X POST "https://heldsway.com/api/v1/affiliates/register" \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{
"name": "John Smith",
"email": "john@example.com",
"password": "MyPassword123!"
}'Success Response — 201 Created
json
{
"success": true,
"message": "Registration submitted. Pending approval.",
"data": {
"id": 55,
"referral_code": "XK9P2QR7",
"status": "pending",
"commission_rate": null,
"notes": null,
"approved_at": null,
"suspended_at": null,
"terminated_at": null,
"created_at": "2026-04-13T11:30:00.000000Z",
"affiliate_user": {
"id": 12,
"name": "John Smith",
"email": "john@example.com",
"phone": null
}
}
}Error Responses
| Status | Code | Description |
|---|---|---|
403 | REGISTRATION_DISABLED | allow_self_registration is not enabled for this business |
409 | AFFILIATE_EXISTS | This email is already an affiliate of your business |
422 | VALIDATION_ERROR | Missing or invalid fields |
Update Affiliate
Update editable fields on an existing affiliate. Only include fields you want to change — all fields are optional.
PATCH /v1/affiliates/{id}
- Required scope:
affiliates:write - Rate limit: 60 requests/minute
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | integer | Affiliate ID |
Request Body
| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
commission_rate | float|null | No | 0–100 | Override rate. Send null to revert to business default |
notes | string|null | No | max 1000 | Internal notes |
Example Request
bash
curl -X PATCH "https://heldsway.com/api/v1/affiliates/42" \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{
"commission_rate": 15.0,
"notes": "Upgraded to premium tier"
}'Success Response — 200 OK
Returns the updated Affiliate Object.
Error Responses
| Status | Code | Description |
|---|---|---|
404 | NOT_FOUND | Affiliate does not exist for this business |
422 | VALIDATION_ERROR | Invalid field values |
Delete Affiliate
Soft-delete an affiliate from your business. This removes the affiliate record but does not delete their user account — they may still be an affiliate for other businesses. Historical conversion and click data is preserved.
DELETE /v1/affiliates/{id}
- Required scope:
affiliates:write - Rate limit: 60 requests/minute
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | integer | Affiliate ID |
Example Request
bash
curl -X DELETE "https://heldsway.com/api/v1/affiliates/42" \
-H "Authorization: Bearer <access_token>"Success Response — 204 No Content
Empty body.
Error Responses
| Status | Code | Description |
|---|---|---|
404 | NOT_FOUND | Affiliate does not exist for this business |
Approve Affiliate
Approve a pending affiliate, moving them to active status and allowing them to start earning commissions.
POST /v1/affiliates/{id}/approve
- Required scope:
affiliates:write - Rate limit: 60 requests/minute
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | integer | Affiliate ID |
Example Request
bash
curl -X POST "https://heldsway.com/api/v1/affiliates/55/approve" \
-H "Authorization: Bearer <access_token>"Success Response — 200 OK
json
{
"success": true,
"message": "Affiliate approved.",
"data": {
"id": 55,
"status": "active",
"approved_at": "2026-04-13T12:00:00.000000Z"
}
}Error Responses
| Status | Code | Description |
|---|---|---|
404 | NOT_FOUND | Affiliate not found |
409 | INVALID_STATUS | Affiliate is not in pending status |
Suspend Affiliate
Suspend an active or pending affiliate. Suspended affiliates cannot earn new commissions. Existing approved commissions are not affected.
POST /v1/affiliates/{id}/suspend
- Required scope:
affiliates:write - Rate limit: 60 requests/minute
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | integer | Affiliate ID |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
reason | string | No | Internal reason for suspension (max 500 chars). Appended to notes. |
Example Request
bash
curl -X POST "https://heldsway.com/api/v1/affiliates/42/suspend" \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{ "reason": "Suspected fraudulent activity under review." }'Success Response — 200 OK
json
{
"success": true,
"message": "Affiliate suspended.",
"data": {
"id": 42,
"status": "suspended",
"suspended_at": "2026-04-13T12:30:00.000000Z"
}
}Error Responses
| Status | Code | Description |
|---|---|---|
404 | NOT_FOUND | Affiliate not found |
409 | INVALID_STATUS | Affiliate is already suspended or terminated |
Reactivate Affiliate
Reactivate a suspended affiliate, restoring them to active status.
POST /v1/affiliates/{id}/reactivate
- Required scope:
affiliates:write - Rate limit: 60 requests/minute
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | integer | Affiliate ID |
Example Request
bash
curl -X POST "https://heldsway.com/api/v1/affiliates/42/reactivate" \
-H "Authorization: Bearer <access_token>"Success Response — 200 OK
json
{
"success": true,
"message": "Affiliate reactivated.",
"data": {
"id": 42,
"status": "active",
"suspended_at": null
}
}Error Responses
| Status | Code | Description |
|---|---|---|
404 | NOT_FOUND | Affiliate not found |
409 | INVALID_STATUS | Affiliate is not suspended |
Terminate Affiliate
Permanently terminate an affiliate. This is irreversible — terminated affiliates cannot be reactivated. Use suspend if you may want to reinstate them later.
POST /v1/affiliates/{id}/terminate
- Required scope:
affiliates:write - Rate limit: 60 requests/minute
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | integer | Affiliate ID |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
reason | string | No | Reason for termination (max 500 chars). Appended to notes. |
Example Request
bash
curl -X POST "https://heldsway.com/api/v1/affiliates/42/terminate" \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{ "reason": "Violated affiliate terms of service." }'Success Response — 200 OK
json
{
"success": true,
"message": "Affiliate terminated.",
"data": {
"id": 42,
"status": "terminated",
"terminated_at": "2026-04-13T13:00:00.000000Z"
}
}Error Responses
| Status | Code | Description |
|---|---|---|
404 | NOT_FOUND | Affiliate not found |
409 | INVALID_STATUS | Affiliate is already terminated |
Get Affiliate Stats
Returns aggregate counts of affiliates grouped by status for your business.
GET /v1/affiliates/stats
- Required scope:
affiliates:read - Rate limit: 120 requests/minute
Example Request
bash
curl "https://heldsway.com/api/v1/affiliates/stats" \
-H "Authorization: Bearer <access_token>"Success Response — 200 OK
json
{
"success": true,
"message": "OK",
"data": {
"total": 120,
"active": 85,
"pending": 20,
"suspended": 10,
"terminated": 5
}
}Response Fields
| Field | Type | Description |
|---|---|---|
total | integer | Total number of affiliates across all statuses |
active | integer | Affiliates with status = active |
pending | integer | Affiliates with status = pending (awaiting approval) |
suspended | integer | Affiliates with status = suspended |
terminated | integer | Affiliates with status = terminated |
Note: Soft-deleted affiliates are excluded from all counts.
totalequals the sum of all four status counts.
Export Affiliates
Downloads affiliates as a CSV file. Supports the same filters as List Affiliates but without pagination — returns all matching records. An additional ids parameter allows exporting a specific selection of affiliates.
GET /v1/affiliates/export
- Required scope:
affiliates:read - Rate limit: 30 requests/minute
Query Parameters
| Parameter | Type | Required | Constraints | Description |
|---|---|---|---|---|
ids | string | No | Comma-separated integers | Export only these affiliate IDs (e.g., 42,55,78). When provided, status and search are ignored |
status | string | No | pending, active, suspended, terminated | Filter by status. Ignored when ids is set |
search | string | No | max:255 | Search by name, email, or referral code. Ignored when ids is set |
sort | string | No | created_at, referral_code, status, commission_rate | Sort field. Default: created_at |
direction | string | No | asc, desc | Sort direction. Default: desc |
Example Request
bash
curl "https://heldsway.com/api/v1/affiliates/export?status=active" \
-H "Authorization: Bearer <access_token>" \
-o active-affiliates.csvSuccess Response — 200 OK
Content-Type: text/csvContent-Disposition: attachment; filename="affiliates-export-2026-04-17.csv"
csv
ID,Name,Email,Phone,Referral Code,Commission Rate,Status,Joined,Approved At,Suspended At,Terminated At,Notes
42,"Jane Doe",jane@example.com,+14155552671,ABC12345,10.00,active,"2026-03-15 14:22:00","2026-04-01 09:00:00",,,"VIP partner"
55,"John Smith",john@example.com,,XK9P2QR7,,pending,"2026-04-13 11:30:00",,,,CSV Columns
| Column | Description |
|---|---|
| ID | Unique affiliate ID |
| Name | Affiliate's full name (empty if no linked user) |
| Affiliate's email address (empty if no linked user) | |
| Phone | Phone number (empty if not set) |
| Referral Code | Unique tracking code used in referral links |
| Commission Rate | Affiliate-specific override rate (%). Empty if inheriting business default |
| Status | Current status: pending, active, suspended, or terminated |
| Joined | When the affiliate record was created (YYYY-MM-DD HH:MM:SS) |
| Approved At | When approved (empty if never approved) |
| Suspended At | When suspended (empty if never suspended) |
| Terminated At | When terminated (empty if not terminated) |
| Notes | Internal notes (may contain newlines; properly CSV-escaped) |
Error Responses
| Status | Code | Description |
|---|---|---|
401 | UNAUTHORIZED | Missing or invalid Bearer token |
403 | FORBIDDEN | Token does not have affiliates:read scope |
422 | VALIDATION_ERROR | Invalid ids format or invalid filter values |
Get Affiliate Stats (Individual)
Returns performance statistics for a single affiliate: total earned commission, pending payouts, total orders, and referral clicks.
GET /v1/affiliates/{id}/stats
- Required scope:
affiliates:read - Rate limit: 120 requests/minute
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | integer | Affiliate ID |
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
date_from | date | — | Start of date range (inclusive). Format: YYYY-MM-DD. Omit for all-time |
date_to | date | — | End of date range (inclusive). Format: YYYY-MM-DD. Must be ≥ date_from |
Example Request
bash
curl "https://heldsway.com/api/v1/affiliates/42/stats?date_from=2026-04-01&date_to=2026-04-30" \
-H "Authorization: Bearer <access_token>"Success Response — 200 OK
json
{
"success": true,
"message": "OK",
"data": {
"total_earned": 175.00,
"pending_payout": 35.00,
"total_orders": 12,
"referral_clicks": 483
}
}Response Fields
| Field | Type | Description |
|---|---|---|
total_earned | float | Sum of commission_amount across all conversions (all statuses) |
pending_payout | float | Sum of commission_amount for conversions with pending status only |
total_orders | integer | Total number of conversions (all statuses) |
referral_clicks | integer | Total number of tracking clicks |
Note: When no date range is specified, all-time totals are returned.
total_earnedincludes commissions in all statuses.
Error Responses
| Status | Code | Description |
|---|---|---|
404 | NOT_FOUND | Affiliate does not exist for this business |
422 | VALIDATION_ERROR | Invalid date format or date_to is before date_from |