Skip to content

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

ParameterTypeDefaultDescription
pageinteger1Page number
per_pageinteger25Results per page. Max 100
statusstringFilter by status: pending | active | suspended | terminated
searchstringSearch across name, email, and referral code
sortstringcreated_atSort field: created_at | referral_code | status | commission_rate
directionstringdescSort 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

ParameterTypeDescription
idintegerAffiliate 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

StatusCodeDescription
404NOT_FOUNDAffiliate 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

FieldTypeRequiredConstraintsDescription
namestringYesmax 255Affiliate's full name
emailstringYesvalid email, max 255Affiliate's email address
passwordstringYesmin 8, max 255Account password
phonestringNomax 30Phone number
commission_ratefloatNo0–100Override commission rate (%). Omit to use business default
notesstringNomax 1000Internal notes
referral_codestringNoalphanumeric, max 32, uniqueCustom 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

StatusCodeDescription
409AFFILIATE_EXISTSThis email is already an affiliate of your business
422VALIDATION_ERRORMissing 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_registration must be enabled. If it is off, this endpoint returns 403. 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

FieldTypeRequiredConstraintsDescription
namestringYesmax 255Applicant's full name
emailstringYesvalid email, max 255Applicant's email
passwordstringYesmin 8, max 255Account password they will use to log in
phonestringNomax 30Phone 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

StatusCodeDescription
403REGISTRATION_DISABLEDallow_self_registration is not enabled for this business
409AFFILIATE_EXISTSThis email is already an affiliate of your business
422VALIDATION_ERRORMissing 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

ParameterTypeDescription
idintegerAffiliate ID

Request Body

FieldTypeRequiredConstraintsDescription
commission_ratefloat|nullNo0–100Override rate. Send null to revert to business default
notesstring|nullNomax 1000Internal 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

StatusCodeDescription
404NOT_FOUNDAffiliate does not exist for this business
422VALIDATION_ERRORInvalid 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

ParameterTypeDescription
idintegerAffiliate 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

StatusCodeDescription
404NOT_FOUNDAffiliate 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

ParameterTypeDescription
idintegerAffiliate 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

StatusCodeDescription
404NOT_FOUNDAffiliate not found
409INVALID_STATUSAffiliate 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

ParameterTypeDescription
idintegerAffiliate ID

Request Body

FieldTypeRequiredDescription
reasonstringNoInternal 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

StatusCodeDescription
404NOT_FOUNDAffiliate not found
409INVALID_STATUSAffiliate 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

ParameterTypeDescription
idintegerAffiliate 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

StatusCodeDescription
404NOT_FOUNDAffiliate not found
409INVALID_STATUSAffiliate 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

ParameterTypeDescription
idintegerAffiliate ID

Request Body

FieldTypeRequiredDescription
reasonstringNoReason 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

StatusCodeDescription
404NOT_FOUNDAffiliate not found
409INVALID_STATUSAffiliate 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

FieldTypeDescription
totalintegerTotal number of affiliates across all statuses
activeintegerAffiliates with status = active
pendingintegerAffiliates with status = pending (awaiting approval)
suspendedintegerAffiliates with status = suspended
terminatedintegerAffiliates with status = terminated

Note: Soft-deleted affiliates are excluded from all counts. total equals 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

ParameterTypeRequiredConstraintsDescription
idsstringNoComma-separated integersExport only these affiliate IDs (e.g., 42,55,78). When provided, status and search are ignored
statusstringNopending, active, suspended, terminatedFilter by status. Ignored when ids is set
searchstringNomax:255Search by name, email, or referral code. Ignored when ids is set
sortstringNocreated_at, referral_code, status, commission_rateSort field. Default: created_at
directionstringNoasc, descSort direction. Default: desc

Example Request

bash
curl "https://heldsway.com/api/v1/affiliates/export?status=active" \
  -H "Authorization: Bearer <access_token>" \
  -o active-affiliates.csv

Success 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

ColumnDescription
IDUnique affiliate ID
NameAffiliate's full name (empty if no linked user)
EmailAffiliate's email address (empty if no linked user)
PhonePhone number (empty if not set)
Referral CodeUnique tracking code used in referral links
Commission RateAffiliate-specific override rate (%). Empty if inheriting business default
StatusCurrent status: pending, active, suspended, or terminated
JoinedWhen the affiliate record was created (YYYY-MM-DD HH:MM:SS)
Approved AtWhen approved (empty if never approved)
Suspended AtWhen suspended (empty if never suspended)
Terminated AtWhen terminated (empty if not terminated)
NotesInternal notes (may contain newlines; properly CSV-escaped)

Error Responses

StatusCodeDescription
401UNAUTHORIZEDMissing or invalid Bearer token
403FORBIDDENToken does not have affiliates:read scope
422VALIDATION_ERRORInvalid 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

ParameterTypeDescription
idintegerAffiliate ID

Query Parameters

ParameterTypeDefaultDescription
date_fromdateStart of date range (inclusive). Format: YYYY-MM-DD. Omit for all-time
date_todateEnd 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

FieldTypeDescription
total_earnedfloatSum of commission_amount across all conversions (all statuses)
pending_payoutfloatSum of commission_amount for conversions with pending status only
total_ordersintegerTotal number of conversions (all statuses)
referral_clicksintegerTotal number of tracking clicks

Note: When no date range is specified, all-time totals are returned. total_earned includes commissions in all statuses.

Error Responses

StatusCodeDescription
404NOT_FOUNDAffiliate does not exist for this business
422VALIDATION_ERRORInvalid date format or date_to is before date_from

Released under the MIT License.