Propper
PlatformFor your team14 of 14
API and webhooks

Your own systems, talking to your firm.

One API host for every firm, where the key decides which firm a call acts for. You choose what each key may do and where it may be called from, every call is kept for 30 days, and every failure comes back with a code your code can branch on. Our own apps are built on the same API.

Requestapi.proppertrading.com
Endpoint
Headers
AuthorizationSent
Bearer sk_live_a1b2c3d4_9f83c…
Idempotency-KeySent
8f14e45f-ea0d-4d1f-9c4b-3e11f0f2c0a1
Same value and same body as a call before: the first answer comes back.
What the API checks
Key
Allowed address
Rate limit299 / 300
Idempotency-KeyPOST only
Scope
Validation
Handled for your firm
This key in your dashboard
Websitea1b2c3d4
Scopes
Allowed addressesAny address
This call comes from 198.51.100.24
Calls on this key
09:41:07GET /v1/ping200
Response200 OK
The same call with curl
curl -X POST https://api.proppertrading.com/v1/affiliates/pre-registrations \
  -H "Authorization: Bearer sk_live_a1b2c3d4_9f83c2e15b7a4d6e8091c3f5a7b9d1e2" \
  -H "Idempotency-Key: 8f14e45f-ea0d-4d1f-9c4b-3e11f0f2c0a1" \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]"}'

The key works. The answer names your firm and every scope the key holds.

X-Request-Id: req_01m6m8z5p2ebr2483wa0aymndsX-RateLimit-Limit: 300X-RateLimit-Remaining: 299
{  "data": {    "ok": true,    "environment": "live",    "api_key": "a1b2c3d4",    "scopes": [      "affiliates:write",      "waitlist:write"    ],    "tenant": {      "name": "Acme Funded",      "slug": "acme"    },    "time": "2026-11-04T09:41:07+00:00"  },  "meta": {    "request_id": "req_01m6m8z5p2ebr2483wa0aymnds"  }}
X-RateLimit-Remaining 299 / 300
Fig. 14 · Try it · A call to the APIA simulation in your browser. Nothing is sent anywhere, and the key is the example from our docs.
kinds of credential: a key for your firm, a token for a person
2
requests a minute per key, counted per key and never per address
300
in which a retried POST gets the first answer back
24 h
days of calls kept per key, to search and export
30
Feature by feature

What the API does, one part at a time.

01

Your launch, driven from your own site

A firm key reaches the two things a marketing site does before and at a launch. It reserves referral codes for future affiliates, and it collects a waitlist with a discount for signing up early. Both run on your own form, and we send the emails in your branding.

  • A reserved code and a claim code, returned once and emailed
  • A reserved link opens a pre-launch page until the affiliate claims it
  • The waitlist reward follows your settings, so a leaked key cannot mint a bigger discount
  • A ping that shows the firm, the environment and the scopes of a key
Core
GET/v1/pingany key
Affiliate pre-registrations
POST/v1/affiliates/pre-registrationsaffiliates:write
GET/v1/affiliates/pre-registrationsaffiliates:read
GET/v1/affiliates/pre-registrations/{id}affiliates:read
POST/v1/affiliates/pre-registrations/{id}/resendaffiliates:write
DELETE/v1/affiliates/pre-registrations/{id}affiliates:write
Waitlist
POST/v1/waitlist/signupswaitlist:write
GET/v1/waitlist/signupswaitlist:read
GET/v1/waitlist/signups/{id}waitlist:read
POST/v1/waitlist/signups/{id}/resendwaitlist:write
DELETE/v1/waitlist/signups/{id}waitlist:write
02

A key for your firm, a token for a person

Two credentials that never overlap. A key acts for your firm, server to server, and holds only firm scopes. A token acts for one person on one device, and can never do more than that person may do in your platform. Neither carries a firm in the address: the credential decides, so a key of one firm can never reach another.

  • Keys are made in your dashboard, tokens by signing in
  • A token can do the narrower of its scopes and the person's role
  • Firm scopes can never be given to a device, and the reverse
  • The secret is stored as a hash and shown exactly once
Your firm

sk_live_a1b2c3d4_9f83c2e15b7a4d6e8091c3f5a7b9d1e2

environment
Made
Under API keys in your dashboard
Acts as
Your firm, within its scopes
Ends
When revoked, or on its end date
A person, on one device

ptat_9f2c1a44_3b8e7d2f5c9a1b4e6d8f0a2c4e6b8d1f

Made
By signing in on the device
Acts as
That person, never more than their role
Ends
On sign out, or after 90 quiet days
03

Only what a key needs, only from where it runs

Each key holds the scopes you tick, and nothing else. It can be held to the addresses of your servers and given an end date. Every change applies to the next call without a new secret, and before you save, the screen warns about what would break.

  • Scopes by resource, where managing includes reading
  • Up to 50 addresses or ranges, IPv4 and IPv6, checked as you save
  • An end on a day you pick, or 30, 90 or 365 days ahead
  • A warning for a scope you remove that was used this week
Affiliates
affiliates:read2 endpoints · 96 calls in 7 daysincluded
affiliates:write3 endpoints · 1,690 calls in 7 days
Waitlist
waitlist:read2 endpoints · Not used in 7 days
waitlist:write3 endpoints · 3,640 calls in 7 days
waitlist:write Removing it fails 3,640 calls a week from the moment you save.
Allowed addresses203.0.113.0/242001:db8:4f0::/4810.0.0.300Not an address
Ends
04

A new secret without a minute of downtime

Rotating gives a key a new secret and keeps its scopes, addresses and history. You choose how long the old secret keeps working beside the new one, deploy the new one, and watch the old one go quiet before it stops.

  • The old secret stops now, or works one more hour, day or week
  • When the old secret was last used, so you know it is safe to stop
  • Never more than two working secrets on one key
  • Revoking stops both at once and cannot be undone
Rotated
Deployed
Old secretNew secret
Accepted× RefusedOld secret last used 4 minutes ago
05

Every call, kept for 30 days

Each key has its own usage: calls and failures over today, the last 7 days or the last 30, each against the period before. Under the chart, the endpoints it called and its failures grouped by status and code, each linked to what the code means. Every call itself is there too.

  • Search calls by request id, path, error code or status
  • Open a call for its endpoint, its answer and what sent it
  • Export every call that matches as a CSV
  • Every change to the key in its activity, with who made it
Endpoints
POST /v1/waitlist/signups3,638 · 19
POST /v1/affiliates/pre-registrations1,690 · 16
GET /v1/ping142 · 0
Failures
409 email_already_on_waitlist16
422 validation_failed13
403 insufficient_scope4
409 email_already_registered2
CallsExport CSV
14:02:11POST /v1/waitlist/signups201
14:01:58POST /v1/waitlist/signups409
13:59:40GET /v1/ping200
06

One shape for every answer

Every answer has the same envelope, and every failure the same error object. Your code branches on a code that never changes meaning once it is published, while the message is prose for whoever reads your logs. Each answer carries a request id that we can find in one search.

  • A type for the class of failure, a stable code inside it
  • A failed validation lists every field, not only the first
  • Ids are strings with a prefix that says what they name
  • Lists page with a cursor, up to 100 at a time, newest first
X-Request-Id: req_01kz4bkr1aj1gv63d8fv3133ey
{  "error": {    "type": "invalid_request_error",    "code": "validation_failed",    "message": "The email address is not valid.",    "param": "email",    "doc_url": "https://proppertrading.com/docs/api/errors#validation_failed",    "errors": {      "email": [        "The email address is not valid."      ]    },    "request_id": "req_01kz4bkr1aj1gv63d8fv3133ey"  }}
type
The class of failure
code
Branch on this
param
The field it is about
doc_url
Where the code is explained
request_id
Matches the X-Request-Id header
07

Safe to retry, and plain about limits

Networks fail after the server has done the work. That is why every POST carries an Idempotency-Key: a retry with the same key and body gets the first answer back instead of doing it twice. Rate limits are counted per key, and every answer says where you stand.

  • The same key with another body is refused, never guessed at
  • Only successful answers are kept, so a fixed request can reuse its key
  • 300 requests a minute per key, or 1,200 on the elevated tier
  • Over the limit, a 429 with Retry-After in seconds
POST /v1/affiliates/pre-registrations · Idempotency-Key: 8f14e45f-ea0d-4d1f-9c4b-3e11f0f2c0a1
First try{"email":"[email protected]"}Connection dropped after the work was done
Retry, same key and body{"email":"[email protected]"}201 CreatedIdempotent-Replayed: true
Same key, another body{"email":"[email protected]"}409idempotency_key_reuse
Left this minuteX-RateLimit-Remaining: 300
X-RateLimit-Limit: 300
08

A webhook for your own news

Your own systems can post headlines to your platform domain. They appear under Custom news, your news rules act on them like on any calendar release, and they reach your own traders only. Posting the same id again changes the headline, which is also what makes a retry safe.

  • A key and a secret per sending system, with an allowlist of addresses or host names
  • Roll a key with the old secret working up to a week
  • Every post kept for 30 days with the answer it got
  • Withdraw a headline with a DELETE on its id
POST https://trade.yourfirm.com/webhooks/news
X-News-Key: nk_ade1a2f0479538f1
X-News-Secret: nks_••••••••••••
{  "id": "fed-statement-2026-10-06",  "title": "Fed emergency statement",  "impact": "high",  "currencies": [    "USD"  ],  "starts_at": "2026-10-06T18:00:00Z",  "duration_minutes": 30}
201 Created
Custom news
Fed emergency statementScheduled
18:00 · 30 minUSD · High impactWebhookYour rules act on it
09

The API our own apps are built on

The same API acts for people. Somebody signs in with their password and second factor and gets a token for that device, and our own phone apps, for mail and for running a firm, are built on it. A person can also sign in for a token of their own, to script what they may already do.

  • One token per device, each signed out on its own
  • A changed password ends every other device
  • Running a firm through the same permissions as the web, with every screen read in the activity log
  • Separate limits for signing in, so guessing a password stays slow
1Email address and password
2Code from the authenticator
3A token for this device
Signed in on
Jamie iPhonePropper Mail · This device
Jamie iPadPropperSign out
For a person/v1/me
ProfileMailCalendarNotificationsAssistant
For running a firm/v1/admin
DashboardPayoutsTicketsFraudSupport
10

Docs that cannot fall behind

Every endpoint has its own page with a real request, a real answer and every error it can return. A check in our build fails when an endpoint has no page or a page names a scope the endpoint does not ask for, so the docs ship with the change or the change does not ship.

  • Every page also as markdown, and one index of them for an AI
  • A changelog with every change to the API, newest first
  • Inside v1 only additions, anything breaking goes to a new version
  • At least six months notice before anything is retired
/docs/api/affiliates/create
Create a pre-registrationReserve a referral code and claim code for an email address.POST/v1/affiliates/pre-registrationsErrors400pre_registration_disabled400missing_idempotency_key409email_already_registered422validation_failed
api:docs:checkEvery endpoint has a pagev1 · additions only
Questions

Questions about the API

Not with a firm key today. A key reaches the ping, affiliate pre-registrations and the waitlist. The scopes for traders, challenges, accounts and payouts are already in the key picker, and the picker says plainly that no endpoint uses them yet.

Not yet. Webhooks from the platform to your systems are not built. What works today is the other direction: your systems post news headlines to your own domain, and your news rules act on them.

No. API calls are part of every plan and are not counted toward your bill. What limits them is the rate: 300 requests a minute per key, or 1,200 on the elevated tier, which we set when your integration needs it.

Rotate it with the old secret stopping now, or revoke it, which stops every secret of the key at once. The key keeps its history, so its Calls tab shows what was called over the last 30 days.

No. The firm comes from the key, never from the address or the request, and the database itself keeps every firm to its own rows. An id that belongs to another firm answers as if it does not exist.

Not yet. Every key works on your live platform. Start with the ping, which needs no scope and shows exactly which firm and scopes a key resolves to, and give a key only the scopes it needs while you build.

Works with

Nothing to connect. These parts already share the same traders, accounts and rules.

Your name on the door.
Our engine behind it.

Book a demo and we'll reach out with a migration plan built for your stack. No setup fees on monthly plans, no hidden costs.