Vendor 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/conversionsor/pbSend conversion data to AffSpace when a customer completes a purchase or signs up. The /api/v1/conversions endpoint is preferred for new integrations. The /pb endpoint is legacy but also supports GET requests with query parameters for systems that don't support POST.
Request Body
| Parameter | Description |
|---|---|
offer_coderequired | Your offer code from the AffSpace dashboard |
click_id | The click_id captured when the customer arrived (from the URL parameter). For test mode, prefix with 'test_'. |
txid | Your order/transaction ID. Prevents duplicate tracking if you send the same conversion twice. |
customer_id | Customer identifier. Required for CPA deduplication. |
event_type | "purchase" or "lead" (defaults to "purchase") |
amount | Sale amount in dollars, e.g. "149.99". Required for CPS/RevShare offers. |
currency | Currency code (USD, EUR, GBP, CAD, AUD). Must match offer currency if provided. |
Example Request
curl -X POST "https://your-site.convex.site/api/v1/conversions" \-H "X-API-Key: your_api_key" \-H "Content-Type: application/json" \-d '{"offer_code": "MYOFFER123","click_id": "0M8K2L9P5QRS","txid": "ORDER-98765","customer_id": "cust_12345","amount": "149.99","currency": "USD"}'
Response
{"success": true,"data": {"tracked": true,"conversionId": "conv_x7k9m2p4","status": "pending","currency": "USD"}}
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_idPrevents duplicate payouts amountSale value for payout calculation |
| 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 |
|---|---|
Missing offer_code | offer_code not provided |
Offer not found | offer_code doesn't match any offer |
Offer not active | Offer is paused, draft, or archived |
Click not found | click_id doesn't match any tracked click |
customer_id required for CPA offers | CPA offer but no customer_id |
amount required for CPS/RevShare/percentage offers | Percentage-based payout but no amount |
amount must be positive | amount is 0 or negative |
Click does not belong to this offer | click_id was for a different offer |
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 endpoints (except conversions) | 30/min |
GET /api/v1/stats | 20/min |
POST /api/v1/conversions, POST /pb | 1,000/min |