API Documentation
Full reference for the Commissia REST API v1
Introduction
The Commissia REST API provides read-only access to your organization's data: sales reps, deals, commission plans, calculation periods, results and summaries.
| Parameter | Type | Description |
|---|---|---|
Base URL | https://app.commissia.com/api/v1 | |
Version | v1 (included in the URL) | |
Format | JSON (application/json) | |
Methods | GET only (read-only) |
Authentication
Every request must include an Authorization header with your API key as a Bearer token.
Keys have the prefix cc_live_ and are displayed only once upon creation. They are stored as SHA-256 hashes.
curl -H "Authorization: Bearer cc_live_your_api_key_here" \
https://app.commissia.com/api/v1/repsAuthentication errors:
| Code | Description |
|---|---|
401 | Missing header, invalid format or revoked key |
403 | Insufficient plan (Growth+ required) |
Pagination
All list endpoints support pagination via the limit and offset parameters.
| Parameter | Type | Description |
|---|---|---|
limit | integer | Number of results (1-100, default: 50) |
offset | integer | Offset from the start (default: 0) |
{
"data": [ ... ],
"pagination": {
"total": 42,
"limit": 50,
"offset": 0,
"has_more": false
}
}For detail endpoints (/reps/:id, etc.), the response does not include a pagination object:
{
"data": { ... }
}Errors
Errors follow a uniform format:
{
"error": {
"message": "Description of the problem",
"status": 401
}
}| HTTP Code | Meaning |
|---|---|
200 | Success |
401 | Unauthenticated (missing, invalid or revoked key) |
403 | Forbidden (insufficient plan) |
404 | Resource not found |
429 | Rate limit exceeded |
500 | Internal server error |
Rate Limiting
Each API key is limited to 60 requests per minute (sliding 60-second window). Beyond that, the API returns a 429 code.
{
"error": {
"message": "Rate limit exceeded",
"status": 429
}
}Wait for the end of the window (60 seconds max) before retrying your requests.
Sales Reps
/api/v1/repsList sales reps/api/v1/reps/:idSales rep detailList parameters:
| Parameter | Type | Description |
|---|---|---|
search | string | Search by last name, first name or email |
include_inactive | boolean | Include deleted sales reps (default: false) |
limit | integer | Pagination (1-100, default: 50) |
offset | integer | Offset (default: 0) |
curl -H "Authorization: Bearer cc_live_xxx" \
"https://app.commissia.com/api/v1/reps?search=dupont"{
"data": [
{
"id": "uuid",
"first_name": "Jean",
"last_name": "Dupont",
"email": "jean.dupont@example.com",
"external_id": null,
"start_date": "2025-01-01",
"end_date": null,
"is_active": true,
"created_at": "2025-01-15T10:00:00Z",
"updated_at": "2025-01-15T10:00:00Z"
}
],
"pagination": {
"total": 1,
"limit": 50,
"offset": 0,
"has_more": false
}
}Deals
/api/v1/dealsList deals/api/v1/deals/:idDeal detailList parameters:
| Parameter | Type | Description |
|---|---|---|
search | string | Search by deal name |
rep_id | uuid | Filter by sales rep |
deal_type | string | Filter by deal type |
close_date_from | date | Min close date (YYYY-MM-DD) |
close_date_to | date | Max close date (YYYY-MM-DD) |
limit | integer | Pagination (1-100, default: 50) |
offset | integer | Offset (default: 0) |
curl -H "Authorization: Bearer cc_live_xxx" \
"https://app.commissia.com/api/v1/deals?rep_id=uuid&close_date_from=2025-01-01&close_date_to=2025-03-31"{
"data": [
{
"id": "uuid",
"deal_name": "Acme Corp - Annual License",
"deal_type": "New",
"amount": "15000.00",
"currency": "EUR",
"close_date": "2025-02-15",
"stage": "Won",
"external_id": null,
"product_category": "SaaS",
"rep_id": "uuid",
"crm_source": null,
"created_at": "2025-02-10T14:30:00Z",
"updated_at": "2025-02-10T14:30:00Z"
}
],
"pagination": {
"total": 1,
"limit": 50,
"offset": 0,
"has_more": false
}
}Commission Plans
/api/v1/plansList plans/api/v1/plans/:idPlan detail (with rules)List parameters:
| Parameter | Type | Description |
|---|---|---|
include_inactive | boolean | Include deleted plans (default: false) |
limit | integer | Pagination (1-100, default: 50) |
offset | integer | Offset (default: 0) |
curl -H "Authorization: Bearer cc_live_xxx" \
https://app.commissia.com/api/v1/plans/uuid{
"data": {
"id": "uuid",
"name": "Sales Plan Q1 2025",
"description": "Standard sales team plan",
"effective_from": "2025-01-01",
"effective_to": "2025-03-31",
"is_active": true,
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-01T00:00:00Z",
"rules": [
{
"id": "uuid",
"name": "10% Commission",
"rule_type": "percentage",
"priority": 1,
"conditions": {
"deal_type": "New",
"min_amount": "1000",
"max_amount": null
},
"calculation": {
"rate": "0.10"
},
"is_active": true,
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-01T00:00:00Z"
}
]
}
}Calculation Periods
/api/v1/periodsList periods/api/v1/periods/:idPeriod detailList parameters:
| Parameter | Type | Description |
|---|---|---|
status | string | Filter by status: draft, calculating, review, approved, paid |
limit | integer | Pagination (1-100, default: 50) |
offset | integer | Offset (default: 0) |
curl -H "Authorization: Bearer cc_live_xxx" \
"https://app.commissia.com/api/v1/periods?status=approved"{
"data": [
{
"id": "uuid",
"name": "January 2025",
"period_start": "2025-01-01",
"period_end": "2025-01-31",
"status": "approved",
"calculated_at": "2025-02-01T09:00:00Z",
"approved_at": "2025-02-03T14:00:00Z",
"paid_at": null,
"payment_notes": null,
"created_at": "2025-01-31T10:00:00Z",
"updated_at": "2025-02-03T14:00:00Z"
}
],
"pagination": {
"total": 1,
"limit": 50,
"offset": 0,
"has_more": false
}
}Commission Results
/api/v1/periods/:id/resultsDetailed results for a periodEach result represents the commission calculated for a deal according to a specific rule. A deal can generate multiple results if several rules of the same priority apply. Only the highest priority group (lowest number) is used.
Parameters:
| Parameter | Type | Description |
|---|---|---|
rep_id | uuid | Filter by sales rep |
limit | integer | Pagination (1-100, default: 50) |
offset | integer | Offset (default: 0) |
curl -H "Authorization: Bearer cc_live_xxx" \
"https://app.commissia.com/api/v1/periods/uuid/results?rep_id=uuid"{
"data": [
{
"id": "uuid",
"period_id": "uuid",
"rep_id": "uuid",
"deal_id": "uuid",
"rule_id": "uuid",
"base_amount": "15000.00",
"commission_amount": "1500.00",
"calculation_details": {
"rule_type": "percentage",
"rate": "0.10",
"cap_applied": true,
"uncapped_amount": "2000.00"
},
"adjustment_total": "200.00",
"created_at": "2025-02-01T09:00:00Z"
}
],
"pagination": {
"total": 1,
"limit": 50,
"offset": 0,
"has_more": false
}
}The cap_applied and uncapped_amount fields in calculation_details are present when a per-rule cap has been applied. The adjustment_total field is present when manual adjustments exist for this specific result.
Summaries
/api/v1/periods/:id/summariesSummaries for a period/api/v1/summariesAll summaries (cross-period)Summaries aggregate commissions per sales rep per period: number of deals, total revenue and total commission.
Parameters /periods/:id/summaries:
| Parameter | Type | Description |
|---|---|---|
rep_id | uuid | Filter by sales rep |
limit | integer | Pagination (1-100, default: 50) |
offset | integer | Offset (default: 0) |
Parameters /summaries:
| Parameter | Type | Description |
|---|---|---|
period_id | uuid | Filter by period |
rep_id | uuid | Filter by sales rep |
limit | integer | Pagination (1-100, default: 50) |
offset | integer | Offset (default: 0) |
curl -H "Authorization: Bearer cc_live_xxx" \
https://app.commissia.com/api/v1/periods/uuid/summaries{
"data": [
{
"id": "uuid",
"period_id": "uuid",
"rep_id": "uuid",
"total_deals": 12,
"total_revenue": "180000.00",
"total_commission": "18000.00",
"quota_target": "200000.00",
"quota_attainment": "0.9000",
"cap_amount": "20000.00",
"uncapped_commission": "22000.00",
"adjustment_total": "500.00",
"created_at": "2025-02-01T09:00:00Z",
"updated_at": "2025-02-01T09:00:00Z"
}
],
"pagination": {
"total": 1,
"limit": 50,
"offset": 0,
"has_more": false
}
}The quota_target and quota_attainment fields are present only when a quota is defined on the plan or overridden for the sales rep. Attainment is expressed as a ratio (1.0 = 100%).
The cap_amount and uncapped_commission fields are present only when a cap is configured. total_commission reflects the amount after the cap is applied.
The adjustment_total field is present when manual adjustments exist for this sales rep during this period. Positive amount = bonus, negative = deduction. Final total = total_commission + adjustment_total.
Webhooks
Outbound webhooks notify your server in real time when an event occurs in Commissia. Configure your endpoints from Settings > API & Webhooks > Webhooks.
Available events:
| Event | Description |
|---|---|
period.calculated | Period calculated |
period.approved | Period approved |
period.paid | Period paid |
deal.created | Deal created |
deal.imported | Deals imported (CSV or CRM) |
rep.created | Sales rep created |
rep.updated | Sales rep updated |
rep.deleted | Sales rep deleted |
plan.created | Plan created |
plan.updated | Plan updated |
plan.deleted | Plan deleted |
ping | Connectivity test |
Payload format:
{
"event": "period.approved",
"data": {
"id": "uuid",
"name": "January 2025",
"status": "approved"
},
"timestamp": "2025-02-03T14:00:00.000Z"
}Headers sent:
| Header | Description |
|---|---|
Content-Type | application/json |
X-Webhook-Signature | HMAC-SHA256 signature of the body |
X-Webhook-Event | Event name |
X-Webhook-Delivery-Id | Unique delivery identifier |
Signature verification:
The X-Webhook-Signature header contains an HMAC-SHA256 of the raw request body, signed with your webhook secret. Verify it to authenticate requests.
import { createHmac, timingSafeEqual } from "crypto";
function verifySignature(body: string, signature: string, secret: string): boolean {
const expected = createHmac("sha256", secret)
.update(body)
.digest("hex");
return timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// In your handler:
const rawBody = await request.text();
const signature = request.headers.get("X-Webhook-Signature");
if (!verifySignature(rawBody, signature, WEBHOOK_SECRET)) {
return new Response("Invalid signature", { status: 401 });
}
const payload = JSON.parse(rawBody);Retry policy:
If your endpoint responds with a non-2xx code or does not respond within 10 seconds, Commissia automatically retries:
| Attempt | Delay |
|---|---|
| 2nd attempt | 30 seconds |
| 3rd attempt | 2 minutes |
After 3 failed attempts, the delivery is marked as failed. View delivery history in the Deliveries tab of the API & Webhooks page.