Skip to content
Proofline

Reference

REST API

Base URL: your Proofline platform plus /api/v1, https://app.proofline.link/api/v1. JSON in, JSON out. In the examples, $PROOFLINE_URL is your platform URL, https://app.proofline.link.

Authentication

Create a secret key in Settings → API keys. It is shown once and stored only as a SHA-256 hash.

curl "$PROOFLINE_URL/api/v1/creators" \
  -H "Authorization: Bearer sk_live_…"

Keys have scopes. read reads creators, programs, links, codes, attributions, commissions and receipts. write does everything read does, creates resources, reviews commissions (POST /commissions/{id}/review) and reads payouts: payout batches are finance data, so even GET /payouts needs a write key. Full access (*) is everything the API allows. A key without the scope gets 403; a missing, invalid or revoked key gets 401.

Idempotency

Every POST requires an Idempotency-Key header (1–255 characters). Keys are scoped to the API key that sends them: two API keys never share an answer, even with the same Idempotency-Key. The first response for a key is stored and replayed for 24 hours, 4xx errors included, but 401 and 403 answers are never stored (nor are 5xx ones): once the API key or its scope is fixed, a retry with the same Idempotency-Key runs. Reusing a key with a different body returns 409 conflict. Bodies are JSON up to 256 KB; a larger one gets 413.

curl -X POST "$PROOFLINE_URL/api/v1/creators" \
  -H "Authorization: Bearer sk_live_…" \
  -H "Idempotency-Key: invite-sarah-2026-10-21" \
  -H "Content-Type: application/json" \
  -d '{"programId":"6f1c…","email":"sarah@example.com","name":"Sarah Lee","handle":"sarahmoves"}'

Pagination

List endpoints accept ?limit= (1–200, default 50) and ?cursor=, plus optional appId, programId and creatorId filters (payout batches belong to the organization and take none of these three), and return:

{ "data": [ … ], "nextCursor": "…" }

Errors

Every error has the same shape:

{ "error": { "code": "validation_failed", "message": "Request validation failed", "details": [ … ] } }
Status code When
400 bad_request Malformed JSON, or no Idempotency-Key
401 unauthorized Missing, invalid or revoked key
403 forbidden The key lacks the scope
404 not_found No such resource, or an unknown /api/v1 path
405 bad_request The route doesn’t take that method; Allow lists the ones it does
409 conflict Idempotency key reused, or a state conflict
413 bad_request Body over 256 KB
422 validation_failed Body or query failed validation (details)
429 rate_limited Over 600 requests a minute per key
503 feature_disabled, unavailable Not configured, or temporarily unavailable
500 internal Our fault

Resources

Resource List Get Create
creators GET /creators GET /creators/{id} POST /creators (invite)
programs GET /programs GET /programs/{id} POST /programs
links GET /links GET /links/{id} POST /links
codes GET /codes GET /codes/{id} POST /codes
attributions GET /attributions GET /attributions/{id} —
commissions GET /commissions GET /commissions/{id} —
payouts GET /payouts (batches) GET /payouts/{id} —
receipts GET /receipts GET /receipts/{commissionId} —

Filters

Besides the filters above, lists take status, and GET /commissions also takes kind. An unknown value is a 422.

List status
GET /creators invited, applied, active, rejected, removed
GET /programs active, paused, archived
GET /links active, disabled
GET /codes active, exhausted, expired, revoked
GET /attributions provisional, attributed, locked, void
GET /commissions pending, approved, locked, paid, reversed, void
GET /payouts draft, pending_approval, approved, funding, paid, failed, cancelled

kind on commissions is earning, reversal or adjustment. GET /receipts takes no status.

Create bodies

  • creators: programId, email, name, optional handle, country, planOverrideId, sendEmail (default true) and activate (default false). With activate the membership starts active, so you can issue links and codes at once. A creator who has already claimed their profile is invited instead: joining needs their consent, so they accept the invitation themselves.
  • programs: appId, name, optional currency (default USD) and rules (see windows and holds). A new program has no commission plan yet, so it earns nothing until you add one under Programs → Commission plan in the dashboard; the API can’t add plans, and the Integration Doctor flags active programs without one.
  • links: programId, creatorId, optional slug, landing, destination.
  • codes: programId, creatorId, store (apple, google or internal), code, optional storeOfferRef, offerLabel, redemptionLimit, expiresAt.

Reviewing commissions

POST /commissions/{id}/review (a write key and an Idempotency-Key) approves or voids a commission held for review: an earning in pending (no autopay, contested, over the monthly cap, estimated store money, a renewal Proofline could not place in its subscription) or a reinstated refund. Body: decision (approve or void) and reason (3–500 characters). It answers 200 with { "data": { "commission": …, "changed": [ … ] } }; changed lists every row the decision moved, such as linked partial-refund rows.

  • approve: the commission becomes approved and locks when its hold ends. 409 conflict while an open fraud flag holds it.
  • void: the commission and its unlocked linked rows become void, the creator's balance is reduced and commission.reversed is sent. Locked or paid commissions return 409; correct them with an adjustment in the dashboard.

GET /receipts lists commission receipts, newest first, with the usual appId, programId, creatorId filters and cursor paging.

Money fields are integer minor units with an ISO currency; rates are basis points.