Advertiser API
Connect your platform to AffSpace and track affiliate-driven sales automatically.
Accurate Attribution
Every sale traced to the affiliate who drove it
Real-time Data
See conversions the moment they happen
Automated Payouts
Affiliates paid based on tracked sales
Quick Start
Capture the click_id — Save the click_id URL parameter when visitors arrive from affiliate links.
Report conversions — POST to /api/v1/conversions when they purchase.
Authentication
Get your API key from the Integration page. Include it in every request:
X-API-Key: your_api_key# AlternativeAuthorization: Bearer your_api_key
Report Conversions
/api/v1/conversionsSend primary conversion data to AffSpace when a customer completes a payable action. Use POST /api/v1/conversions for server-side JSON payloads. Use named GET /pb/{endpointId} callbacks only when your tracker requires query-string delivery.
Request Body
| Parameter | Description |
|---|---|
clickid | The click_id captured when the customer arrived. Aliases: click_id, cid. For test mode, prefix with 'test_'. |
sum | Sale amount in dollars, e.g. "149.99". Aliases: amount, revenue. Required for CPS offers. |
action_id | Your order/transaction ID. Aliases: txid, order_id. Prevents duplicate tracking. |
user_id | Customer identifier. Aliases: customer_id. Required for CPA deduplication. |
goal | Event type. Aliases: event, event_type. Defaults to "purchase". |
securerequired | Your API key. Can also be passed via X-API-Key header. |
Example Request
# Primary conversion APIcurl -X POST "https://api.affs.space/api/v1/conversions" \-H "Content-Type: application/json" \-H "X-Api-Key: your_api_key" \-d '{"click_id": "0M8K2L9P5QRS","amount": "149.99","txid": "ORDER-98765","customer_id": "cust_12345"}'
Response
{"success": true,"data": {"tracked": true,"conversionId": "conv_x7k9m2p4","status": "pending","currency": "USD"}}
Track Secondary Events
/api/v1/eventsor/pb/{endpointId}Track non-paying funnel events such as pageview, registration, and lead. Use POST /api/v1/events for server-side JSON calls. Use GET /pb/{endpointId} when your tracker only supports query-string callbacks. The named endpoint determines whether the callback is primary or secondary.
Request Body
| Parameter | Description |
|---|---|
click_idrequired | The click_id captured when the customer arrived. Aliases: clickid, cid. |
event_typerequired | Secondary event type. Supported values: "pageview", "registration", "lead". |
url | Page URL where the event happened. |
referrer | Referrer URL for the event. |
securerequired | Your API key. Can also be passed via X-API-Key header. |
Example Request
curl -X POST "https://api.affs.space/api/v1/events" \-H "Content-Type: application/json" \-H "X-Api-Key: your_api_key" \-d '{"click_id": "0M8K2L9P5QRS","event_type": "lead","url": "https://advertiser.example/signup","referrer": "https://advertiser.example/pricing"}'
Response
{"success": true,"data": {"tracked": true,"event_id": "evt_f93xk2m1","reason": null}}
Understanding Commission Types
| Type | How it works | Required fields |
|---|---|---|
| CPA Cost Per Action | Fixed amount per conversion, regardless of sale value.e.g., $30 per signup | customer_idRecommended for duplicate prevention |
| CPS Cost Per Sale | Percentage of each sale value.e.g., 15% of order total | amountSale value used to calculate payout |
| RevShare Revenue Share | Ongoing percentage for recurring revenue.e.g., 20% of subscription payments | amountPayment amount being shared |
Always submit the full sale value in amount — AffSpace calculates referral commissions automatically based on your offer terms.
Duplicate Prevention
Include txid (your order ID) to prevent double-tracking on retries. Duplicate txids are acknowledged but not re-tracked.
List Conversions
/api/v1/conversionsRetrieve your conversion history with filters for reconciliation and reporting.
Query Parameters
| Parameter | Description |
|---|---|
offer_code | Filter by specific offer |
status | pending, approved, rejected, reversed |
start_date | Unix timestamp in milliseconds |
end_date | Unix timestamp in milliseconds |
limit | Results per page (max 500) |
cursor | Pagination cursor |
Response
{"success": true,"data": [{"id": "conv_x7k9m2p4","offerCode": "MYOFFER123","vendorTxId": "ORDER-98765","currency": "USD","saleAmountCents": 14999,"advertiserPayoutCents": 3000,"status": "approved","createdAt": 1706234567890}],"meta": { "pagination": { "hasMore": true, "nextCursor": "..." } }}
Get Conversion
/api/v1/conversions/{id}Get details for a specific conversion.
Response
{"success": true,"data": {"id": "conv_x7k9m2p4","offerCode": "MYOFFER123","vendorTxId": "ORDER-98765","currency": "USD","saleAmountCents": 14999,"advertiserPayoutCents": 3000,"status": "approved","createdAt": 1706234567890}}
Get Statistics
/api/v1/statsAggregated performance data across your offers — clicks, conversions, revenue, and conversion rates.
Query Parameters
| Parameter | Description |
|---|---|
offer_code | Filter to specific offer |
start_date | Start of range (default: 30 days ago) |
end_date | End of range (default: now) |
group_by | day, week, or month for time series |
Response
{"success": true,"data": {"summary": {"totalClicks": 12500,"totalConversions": 487,"approvedConversions": 412,"totalRevenueCents": 1236000,"conversionRate": "3.90"},"byOffer": [{"offerCode": "MYOFFER123","offerName": "My Product Offer","currency": "USD","clicks": 5000,"conversions": 200,"revenueCents": 600000}],"timeSeries": [{ "date": "2024-01-25", "clicks": 450, "conversions": 18 }]}}
List Offers
/api/v1/offersView all your offers with their status and payout configuration.
Query Parameters
| Parameter | Description |
|---|---|
status | published, paused, draft, archived |
limit | Results per page (max 100) |
cursor | Pagination cursor |
Response
{"success": true,"data": [{"code": "MYOFFER123","name": "My Product Offer","status": "published","currency": "USD","commissionType": "cpa","payoutTerms": { "advertiserPayoutCents": 3000 }}]}
Get Offer
/api/v1/offers/{code}Get full details for a specific offer by its code.
Response
{"success": true,"data": {"code": "MYOFFER123","name": "My Product Offer","status": "published","currency": "USD","primaryUrl": "https://...","payoutTerms": { "advertiserPayoutCents": 3000 }}}
Get Profile
/api/v1/profileYour vendor account information.
Response
{"success": true,"data": {"companyName": "Acme Inc","contactEmail": "team@acme.com","status": "approved","hasApiKey": true}}
Create Test Session
/api/v1/test-sessionsGenerate a test click_id to validate your integration without creating real conversions or triggering payouts.
Request Body
| Parameter | Description |
|---|---|
offer_coderequired | Offer to test |
Response
{"success": true,"data": {"testClickId": "test_0M8K2L9P5QRS","sessionToken": "abc123...","expiresAt": 1706234867890}}
Get Test Session
/api/v1/test-sessions/{token}Check validation results after sending a test conversion.
Response
{"success": true,"data": {"status": "received","validation": { "signatureValid": true, "fieldsValid": true }}}
Health Check
/healthReturns the API health status. Does not require authentication.
Response
{"status": "ok","timestamp": 1706234567890}
Error Handling
All errors return a consistent format:
{"success": false,"error": {"code": "VALIDATION_ERROR","message": "Click not found"}}
Error Codes
| Code | Status | Description |
|---|---|---|
UNAUTHORIZED | 401 | API key required |
INVALID_API_KEY | 401 | API key is invalid |
VALIDATION_ERROR | 400 | Invalid request — see message for details |
NOT_FOUND | 404 | Resource not found |
RATE_LIMITED | 429 | Too many requests — check Retry-After header |
INTERNAL_ERROR | 500 | Server error |
Conversion Validation Errors
These return status 400 with code VALIDATION_ERROR
| Message | Cause |
|---|---|
click_id is required | click_id not provided |
Offer not found | Click points to an offer that no longer exists |
Offer not active | Offer is paused, draft, or archived |
Click not found | click_id doesn't match any tracked click |
Unauthorized - click belongs to different vendor | API key belongs to a different advertiser |
amount required for CPS/RevShare/percentage offers | Percentage-based payout but no amount |
amount must be positive | amount is 0 or negative |
Acknowledged but Not Tracked
These return success: true with tracked: false. Your integration is working — the conversion just doesn't qualify for additional payout.
{"success": true,"tracked": false,"reason": "cpa_customer_limit","message": "Conversion received. This customer already converted..."}
| Reason | Explanation |
|---|---|
cpa_customer_limit | Customer already converted under this CPA offer |
cpa_click_limit | Click already converted under this CPA offer |
duplicate_txid | Conversion already recorded with this transaction ID |
Rate Limits
Per API key. Check Retry-After header if limited.
| Endpoint | Limit |
|---|---|
GET endpoints | 100/min |
POST /api/v1/events and other write endpoints | 30/min |
GET /api/v1/stats | 20/min |
POST /api/v1/conversions, GET /pb/{endpointId} (primary endpoints) | 1,000/min |