Referral Links
List All Links
List all referral links across all affiliates for your business.
GET /v1/links
- 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 |
affiliate_id |
integer | — | Filter to a specific affiliate |
is_active |
integer | — | Filter by active state: 1 (active only) or 0 (inactive only) |
search |
string | — | Search slug, destination URL, campaign, or affiliate name/email |
sort |
string | created_at |
Sort field: created_at | slug | click_count | destination_url | campaign |
direction |
string | desc |
asc | desc |
Example Request
curl "api.heldsway.com/api//v1/links?is_active=1&per_page=20" \
-H "Authorization: Bearer <access_token>"
Success Response — 200 OK
{
"success": true,
"message": "OK",
"data": {
"items": [
{
"id": 10,
"affiliate_id": 42,
"slug": "summer2026",
"destination_url": "https://example.com/landing",
"campaign": "Summer Campaign",
"is_active": true,
"click_count": 142,
"tracking_url": "https://yourbusiness.heldsway.com/r/summer2026",
"metadata": null,
"created_at": "2026-04-01T09:00:00.000000Z"
}
],
"meta": {
"current_page": 1,
"per_page": 20,
"total": 45,
"last_page": 3
}
}
}
List Links for Affiliate
List referral links belonging to a specific affiliate.
GET /v1/affiliates/{affiliateId}/links
- Required scope:
affiliates:read - Rate limit: 120 requests/minute
Path Parameters
| Parameter | Type | Description |
|---|---|---|
affiliateId |
integer | Affiliate ID |
Query Parameters
Same as List All Links, excluding affiliate_id.
Example Request
curl "api.heldsway.com/api//v1/affiliates/42/links" \
-H "Authorization: Bearer <access_token>"
Success Response — 200 OK
Same structure as List All Links.
Error Responses
| Status | Code | Description |
|---|---|---|
404 |
NOT_FOUND |
Affiliate not found for this business |
Create Referral Link
Create a new referral link for a specific affiliate.
POST /v1/affiliates/{affiliateId}/links
- Required scope:
affiliates:write - Rate limit: 60 requests/minute
Path Parameters
| Parameter | Type | Description |
|---|---|---|
affiliateId |
integer | Affiliate ID |
Request Body
| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
destination_url |
string | Yes | valid URL, max 2048 | Where visitors are redirected after click tracking |
slug |
string | No | alphanumeric + hyphens/underscores, max 64, unique | Custom URL slug. Auto-generated if omitted |
campaign |
string | No | max 255 | Campaign label for grouping and reporting |
is_active |
boolean | No | — | Defaults to true |
metadata |
object | No | — | Arbitrary key-value data for your own use |
Example Request
curl -X POST "api.heldsway.com/api//v1/affiliates/42/links" \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{
"destination_url": "https://example.com/promo",
"slug": "jane-promo",
"campaign": "Spring 2026",
"metadata": { "source": "newsletter" }
}'
Success Response — 201 Created
{
"success": true,
"message": "Created",
"data": {
"id": 11,
"affiliate_id": 42,
"slug": "jane-promo",
"destination_url": "https://example.com/promo",
"campaign": "Spring 2026",
"is_active": true,
"click_count": 0,
"tracking_url": "https://yourbusiness.heldsway.com/r/jane-promo",
"metadata": { "source": "newsletter" },
"created_at": "2026-04-13T10:00:00.000000Z"
}
}
Error Responses
| Status | Code | Description |
|---|---|---|
404 |
NOT_FOUND |
Affiliate not found for this business |
422 |
VALIDATION_ERROR |
Invalid fields or slug already taken |
Bulk Create Referral Links
Create referral links for multiple products in a single request. Links are created asynchronously via a queue job — the endpoint returns immediately with a batch_id for polling.
No limit on the number of items per request (the queue handles scale).
POST /v1/affiliates/{affiliateId}/links?bulk_create=true
- Required scope:
affiliates:write - Rate limit: 60 requests/minute
Path Parameters
| Parameter | Type | Description |
|---|---|---|
affiliateId |
integer | Affiliate ID |
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
bulk_create |
string | Yes | Must be "true" to activate bulk mode |
Request Body
| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
links |
array | Yes | min 1 item | Array of link objects to create |
links[].destination_url |
string | Yes | valid URL, max 2048 | Where visitors are redirected |
links[].slug |
string | No | alphanumeric + hyphens/underscores, max 64, unique, distinct within batch | Custom URL slug. Auto-generated if omitted |
links[].campaign |
string | No | max 255 | Campaign label for grouping |
links[].is_active |
boolean | No | — | Defaults to true |
links[].metadata |
object | No | — | Arbitrary key-value data |
Example Request
curl -X POST "api.heldsway.com/api//v1/affiliates/42/links?bulk_create=true" \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{
"links": [
{
"destination_url": "https://rentmy.com/product/kayak",
"campaign": "Summer 2026"
},
{
"destination_url": "https://rentmy.com/product/tent",
"slug": "tent-deal",
"campaign": "Summer 2026"
},
{
"destination_url": "https://rentmy.com/product/bike",
"campaign": "Summer 2026",
"metadata": { "product_id": "bike-001" }
}
]
}'
Accepted Response — 202 Accepted
The request was accepted and queued for processing.
{
"success": true,
"message": "Bulk creation queued.",
"data": {
"batch_id": 17,
"status": "pending",
"total_items": 3,
"status_url": "/v1/affiliates/42/link-batches/17"
}
}
Error Responses
| Status | Code | Description |
|---|---|---|
404 |
NOT_FOUND |
Affiliate not found for this business |
422 |
VALIDATION_ERROR |
Empty array, missing destination_url, duplicate slugs within batch |
Update Referral Link
Update an existing referral link. The slug and affiliate_id are immutable after creation.
PATCH /v1/links/{id}
- Required scope:
affiliates:write - Rate limit: 60 requests/minute
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id |
integer | Referral link ID |
Request Body
All fields optional — only include what you want to change.
| Field | Type | Constraints | Description |
|---|---|---|---|
destination_url |
string | valid URL, max 2048 | New redirect destination |
campaign |
string|null | max 255 | Updated campaign label. Send null to clear |
is_active |
boolean | — | Enable or disable the link |
metadata |
object|null | — | Replace metadata. Send null to clear |
Example Request
curl -X PATCH "api.heldsway.com/api//v1/links/11" \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{
"is_active": false,
"campaign": "Spring 2026 (ended)"
}'
Success Response — 200 OK
Returns the updated Referral Link Object.
Error Responses
| Status | Code | Description |
|---|---|---|
404 |
NOT_FOUND |
Link not found for this business |
422 |
VALIDATION_ERROR |
Invalid field values |
Delete Referral Link
Soft-delete a referral link. The tracking URL will stop working. Historical click data is preserved.
DELETE /v1/links/{id}
- Required scope:
affiliates:write - Rate limit: 60 requests/minute
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id |
integer | Referral link ID |
Example Request
curl -X DELETE "api.heldsway.com/api//v1/links/11" \
-H "Authorization: Bearer <access_token>"
Success Response — 204 No Content
Empty body.
Error Responses
| Status | Code | Description |
|---|---|---|
404 |
NOT_FOUND |
Link not found for this business |
Get Link Stats
Returns aggregate statistics for all referral links in your business.
GET /v1/links/stats
- Required scope:
affiliates:read - Rate limit: 120 requests/minute
Example Request
curl "api.heldsway.com/api//v1/links/stats" \
-H "Authorization: Bearer <access_token>"
Success Response — 200 OK
{
"success": true,
"message": "OK",
"data": {
"total": 42,
"active": 38,
"inactive": 4,
"total_clicks": 1523
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
total |
integer | Total number of referral links (active + inactive) |
active |
integer | Links with is_active = true |
inactive |
integer | Links with is_active = false |
total_clicks |
integer | Sum of click_count across all links |
Note: Soft-deleted links are excluded from all counts.
total_clicksis derived from the denormalizedclick_countfield on each link, which is incremented in real time by the click tracking system.