API Documentation
Integrate LinkQuill into your workflow with our REST API.
Getting Started
The LinkQuill API lets you programmatically manage programs, affiliates, conversions, payouts, and analytics. All endpoints live under /api/v1/ext/ and require an API key for authentication.
Quick start
- Go to Dashboard → Settings → API Keys and create a key. Choose the scopes you need (e.g.
read:programs,write:conversions). - Copy the key — it starts with
pky_and is only shown once. - Make your first request:
curl https://linkquill.net/api/v1/ext/programs \
-H "Authorization: Bearer pky_your_key_here"API access requires a Starter plan or above. Free plan keys will receive a 403 with code PLAN_LIMIT.
Authentication
Include your API key as a Bearer token in every request:
Authorization: Bearer pky_your_key_hereEach key has scopes that control what it can access. Available scopes:
| Scope | Access |
|---|---|
read:programs | List and view programs |
read:affiliates | List affiliate memberships |
read:conversions | List conversions |
write:conversions | Create and review conversions |
read:payouts | List payouts |
read:analytics | Brand analytics summary |
If a request requires a scope your key doesn't have, you'll get a 403 listing the missing scopes.
Rate Limits
All external API endpoints share a limit of 100 requests per minute per brand, using a sliding window.
When you exceed the limit, the API returns 429 Too Many Requests:
{
"error": {
"code": "RATE_LIMITED",
"message": "Too many requests. Please try again later.",
"details": { "retryAfter": 12 }
}
}The retryAfter field tells you how many seconds to wait before retrying.
Error Codes
All errors follow a consistent format:
{
"error": {
"code": "ERROR_CODE",
"message": "Human-readable description",
"details": { ... }
}
}| Status | Code | Meaning |
|---|---|---|
| 400 | VALIDATION_ERROR | Request body or params failed validation. Check details for field-level errors. |
| 401 | UNAUTHORIZED | Missing, invalid, or expired API key. |
| 403 | FORBIDDEN | Key lacks required scopes, or resource doesn't belong to your brand. |
| 403 | PLAN_LIMIT | Your plan doesn't include API access. Upgrade to Starter or above. |
| 404 | NOT_FOUND | The requested resource doesn't exist (or doesn't belong to your brand). |
| 409 | CONFLICT | State conflict (e.g. reviewing an already-approved conversion). |
| 429 | RATE_LIMITED | Too many requests. Wait and retry. |
Programs
List and view your affiliate programs. Requires the read:programs scope.
/api/v1/ext/programsList all programs for your brand. Supports pagination via ?page=1&limit=25 (max 100).
Auth: Bearer token — read:programs
Response Example
{
"data": {
"programs": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Summer Sale Campaign",
"slug": "summer-sale",
"commissionType": "percentage",
"commissionValue": "15",
"cookieDurationDays": 30,
"isPublic": true,
"createdAt": "2026-01-15T10:00:00Z"
}
],
"pagination": {
"page": 1,
"limit": 25,
"total": 3,
"totalPages": 1,
"hasMore": false
}
}
}cURL Example
curl -X GET "https://linkquill.net/api/v1/ext/programs" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json"/api/v1/ext/programs/:programIdGet a single program by ID. Returns 404 if the program doesn't exist or doesn't belong to your brand.
Auth: Bearer token — read:programs
Response Example
{
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Summer Sale Campaign",
"slug": "summer-sale",
"commissionType": "percentage",
"commissionValue": "15",
"cookieDurationDays": 30,
"minPayoutAmount": "25",
"payoutFrequency": "monthly",
"autoApproveAffiliates": false,
"isPublic": true,
"createdAt": "2026-01-15T10:00:00Z"
}
}cURL Example
curl -X GET "https://linkquill.net/api/v1/ext/programs/:programId" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json"Affiliates
List affiliates across your programs. Requires the read:affiliates scope.
/api/v1/ext/affiliatesList affiliate memberships across all your programs. Filter by ?programId=, ?status= (pending, approved, rejected, suspended). Paginated.
Auth: Bearer token — read:affiliates
Response Example
{
"data": {
"memberships": [
{
"membership": {
"id": "mem_abc123",
"programId": "prog_abc123",
"affiliateId": "aff_def456",
"status": "approved",
"referralCode": "JANE2026",
"trackingLink": "https://linkquill.net/r/JANE2026",
"createdAt": "2026-01-20T08:00:00Z"
},
"affiliate": {
"id": "aff_def456",
"displayName": "Jane Creator"
},
"program": {
"id": "prog_abc123",
"name": "Summer Sale Campaign"
},
"revenueGenerated": 7250.00
}
],
"pagination": {
"page": 1,
"limit": 25,
"total": 15,
"totalPages": 1,
"hasMore": false
}
}
}cURL Example
curl -X GET "https://linkquill.net/api/v1/ext/affiliates" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json"Conversions
List, create, and review conversions. Read operations require read:conversions; write operations require write:conversions.
/api/v1/ext/conversionsList conversions for your brand. Filter by ?status= (pending, approved, rejected, paid, refunded). Paginated.
Auth: Bearer token — read:conversions
Response Example
{
"data": {
"conversions": [
{
"conversion": {
"id": "conv_xyz789",
"programId": "prog_abc123",
"membershipId": "mem_abc123",
"externalOrderId": "order-1234",
"orderAmount": "99.99",
"commissionAmount": "15.00",
"status": "approved",
"attributionType": "link",
"createdAt": "2026-03-05T14:30:00Z"
},
"program": { "name": "Summer Sale Campaign" },
"affiliate": { "displayName": "Jane Creator" }
}
],
"pagination": {
"page": 1,
"limit": 25,
"total": 42,
"totalPages": 2,
"hasMore": true
}
}
}cURL Example
curl -X GET "https://linkquill.net/api/v1/ext/conversions" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json"/api/v1/ext/conversionsCreate a manual conversion. The commission is calculated automatically based on the program's commission structure. The conversion is created as 'approved' immediately.
Auth: Bearer token — write:conversions
Request Body
{
"membershipId": "550e8400-e29b-41d4-a716-446655440000",
"orderId": "order-1234",
"orderAmount": 99.99,
"currency": "USD",
"notes": "Offline sale attribution"
}Response Example
{
"data": {
"id": "conv_new123",
"membershipId": "550e8400-e29b-41d4-a716-446655440000",
"externalOrderId": "order-1234",
"orderAmount": "99.99",
"commissionAmount": "15.00",
"status": "approved",
"attributionType": "manual",
"createdAt": "2026-03-06T12:00:00Z"
}
}cURL Example
curl -X POST "https://linkquill.net/api/v1/ext/conversions" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "membershipId": "550e8400-e29b-41d4-a716-446655440000", "orderId": "order-1234", "orderAmount": 99.99, "currency": "USD", "notes": "Offline sale attribution"}'/api/v1/ext/conversions/:conversionId/reviewApprove or reject a pending conversion. Only works on conversions with status 'pending'. Returns 409 if the conversion has already been reviewed.
Auth: Bearer token — write:conversions
Request Body
{
"status": "approved",
"reason": "Verified purchase"
}Response Example
{
"data": {
"id": "conv_xyz789",
"status": "approved",
"approvedAt": "2026-03-06T12:00:00Z"
}
}cURL Example
curl -X POST "https://linkquill.net/api/v1/ext/conversions/:conversionId/review" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "status": "approved", "reason": "Verified purchase"}'Payouts
View payout history. Requires the read:payouts scope.
/api/v1/ext/payoutsList all payouts for your brand. Filter by ?status= (pending, awaiting_payment, processing, completed, failed). Paginated.
Auth: Bearer token — read:payouts
Response Example
{
"data": {
"payouts": [
{
"payout": {
"id": "pay_mno345",
"affiliateId": "aff_def456",
"amount": "150.00",
"currency": "USD",
"status": "completed",
"stripeTransferId": "tr_abc123",
"periodStart": "2026-02-01T00:00:00Z",
"periodEnd": "2026-02-28T23:59:59Z",
"createdAt": "2026-03-01T00:00:00Z"
},
"affiliate": { "displayName": "Jane Creator" }
}
],
"pagination": {
"page": 1,
"limit": 25,
"total": 8,
"totalPages": 1,
"hasMore": false
}
}
}cURL Example
curl -X GET "https://linkquill.net/api/v1/ext/payouts" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json"Analytics
Get aggregated analytics for your brand. Requires the read:analytics scope.
/api/v1/ext/analyticsBrand analytics summary with top affiliates. Use ?period=7d|30d|90d or ?from=2026-03-01&to=2026-03-07 for a custom range.
Auth: Bearer token — read:analytics
Response Example
{
"data": {
"summary": {
"totalClicks": 12450,
"uniqueClicks": 8320,
"totalConversions": 342,
"revenue": 28750.00,
"commissions": 4312.50,
"pendingConversions": 18,
"activeAffiliates": 24,
"conversionRate": 2.75
},
"topAffiliates": [
{
"affiliateId": "aff_def456",
"displayName": "Jane Creator",
"conversions": 89,
"revenue": 7250.00,
"commissions": 1087.50
}
]
}
}cURL Example
curl -X GET "https://linkquill.net/api/v1/ext/analytics" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json"