Getting started
This page takes you from your first request to your first balance sync. You do every step in test mode, with a test key.
Two ways to integrate
You can offer our markets to your users in two ways. Choose one before you start. The steps on the rest of this page are the same for both.
| Widget | Your own UI on the Market Feed | |
|---|---|---|
| What you build | A place on your page for our ready-made trading screens. You add one script tag and call mount(). | Your own market and trading screens. We give you the markets and the prices as JSON. |
| Who opens a position | The user, in the widget. We send you position.opened. | Your server, with POST /v1/positions. You hold the response, so we send no position.opened for it. |
| Live prices | The widget updates them by itself. | Subscribe to the realtime channel, or poll the Market Feed. |
| What your server calls | User registration, balance sync, and POST /v1/widget/sessions on every page load. | User registration, balance sync, the Market Feed reads and the position calls. |
| Scopes your key needs | write:sync and write:positions | write:sync, write:positions and read:markets |
| Guide | Widget guide | Market Feed guide and Realtime events |
Both ways share the rest of the integration:
- You register each user and report every balance change on your side with a balance sync. The virtual balance in our ledger follows your wallet.
- When a market resolves, we settle the positions and send you
position.settledorposition.voidedwebhooks. - Reconciliation compares our balance with the balance that you report.
The Integration guide shows the widget way from start to finish on one page.
Get an account
Our team creates your account; there is no self sign-up. Once it exists, our team issues your first test key (pmk_test_) and invites you to the tenant portal, where you can issue more. You build and test the whole integration on stage with test keys. Your first live key comes at go-live, when the Go-live checklist passes and our team approves live access. To get an account, write to your Predixum contact.
API key
Every operator request authenticates with a tenant API key:
Authorization: Bearer pmk_test_...Every key belongs to one mode, test or live, and its prefix shows which: pmk_test_ or pmk_live_, followed by 32 characters. The key alone decides the mode of a request. There is no mode parameter and no second address.
- Test keys work from the day your account is created. Use them to build and test your integration, and keep using them after you go live.
- Live keys work once our team approves live access for your account. Asking for a live key before that returns
409 live_access_not_approved.
You can issue a key yourself on the settings screen of the tenant portal. The portal issues the key in the mode it is in. Our team can also issue keys for you. We show the plain-text key once and we do not store it. If you lose it, issue a new one.
You can also rotate a key on the settings screen of the tenant portal. The new key takes the scopes and the mode of the old key. Both keys work during the changeover. When you confirm the changeover, we revoke the old key. This developer portal does not issue or show keys.
A key that starts with pmk_sandbox_ is an older test key. It keeps working as a test key on the same address. New test keys start with pmk_test_.
Use the key from your server only. Do not put it in a browser, a mobile app or the widget configuration. The widget uses a short-lived session token (POST /v1/widget/sessions).
Incoming requests carry no extra signature, timestamp or nonce. TLS and the Bearer key are enough.
Where to integrate
Integrate against stage today. Stage is our sandbox: it runs the same contract as production, and you reach it with a test key (pmk_test_). Production is not open yet. When it opens, we publish its addresses in this table. The paths, the contract and the key format stay the same, so the move changes only the address and the key.
| Environment | Operator API | Market Feed | Widget bundle | Key |
|---|---|---|---|---|
stage | https://test-api.predixum.net | https://test-feed.predixum.net | https://test-cdn.predixum.net | pmk_test_* |
production | Not open yet. We publish its addresses when it opens. |
The Operator API and Market Feed references list the stage address as their server, so you can send their examples to stage as they are.
Test mode and live mode
Test and live mode explains the whole model in one place.
In each environment, both modes use the same address and the same contract: the same endpoints, the same error envelope, the same webhook signature. To go live, you change the key and nothing else.
Test data and live data are fully separate. The users, balances, positions, orders, reports and webhook deliveries that you create with a test key exist only in test mode. A test key cannot reach a live resource, and a live key cannot reach a test resource: the request returns 404 not_found. Rate limits count separately in each mode, so test traffic never uses up your live limits. Test mode is not billed.
Test mode trades the same markets as live mode, and its positions settle when the real market resolves. A test position moves only the prices of your own test mode, never a live price.
Test mode in the tenant portal
The top bar of the tenant portal has a Test mode switch. Until live access is approved, the portal opens in test mode.
The switch changes the data screens (dashboard, users, positions, transactions, reports and reconciliation), the API keys and the webhook endpoint and secret. Everything else belongs to your account and is the same in both modes: your team, support tickets, branding and the widget card theme, billing, the markets you offer and the other settings.
Delete all test data
To start test mode again from an empty account, open the settings screen of the tenant portal in test mode and choose Delete all test data. The owner or an admin of your account can do this. Your test users, balances, positions, orders and reports are gone from test mode afterwards. Your test keys, your test webhook endpoint and secret and your account settings stay, so your integration keeps working against the empty account. Live data is never touched. You cannot undo the deletion.
Live access
When your integration passes the Go-live checklist, our team approves live access and issues your first live key. Your test keys keep working after that, and your test data stays in test mode.
Scopes
Every key carries one or more scopes. A call without the scope returns 403 insufficient_scope.
| Scope | Access it gives |
|---|---|
write:sync | User registration, balance sync (single and batch) and user reads. |
write:positions | Opening and closing a position, limit orders, reads of positions, transactions and rejected attempts, the widget session (POST /v1/widget/sessions) and the realtime token (POST /v1/realtime/tokens). |
read:markets | Market Feed: the market catalog and the prices. |
read:reports | Requesting, polling and downloading operator reports. |
write:tickets | Opening a support ticket from your own tools. |
First user registration
Register a user before you sync a balance or open a position for them:
PUT /v1/users/u-10492
Authorization: Bearer pmk_test_...
Content-Type: application/json
{ "status": "active" }external_user_id is your own user id, and it is opaque to us. It has 1 to 64 characters and contains only A-Z a-z 0-9 . _ ~ -. Do not send an email address or personal data. If your id is an email address, map it to a pseudonymous id first. We store only the id and the status for a user.
The request is naturally idempotent and takes no Idempotency-Key. The status value is active or blocked. A blocked user cannot open a new position, but balance sync is not blocked.
You can read the user and the virtual balance with GET /v1/users/{external_user_id}.
First balance sync
When the balance of a user changes on your side, you send us the difference. We never pull data from your system.
POST /v1/balance-sync
Authorization: Bearer pmk_test_...
Content-Type: application/json
Idempotency-Key: 3f0c9a52-6a8e-4f5b-9a1e-2b7d4c8e1f60
{
"external_user_id": "u-10492",
"direction": "credit",
"amount": "100.00",
"resulting_balance": "100.00"
}directioncarries the sign:creditordebit.amountis always positive.- Amounts are JSON strings (
"100.00"). An amount that you send as a number returns400 validation_failed. resulting_balanceis optional. It is the balance that your system shows after the movement. Reconciliation uses this value as its basis. Reconciliation cannot check an account for which you never send aresulting_balance, and it does not report that account as a discrepancy. We recommend that you send it.Idempotency-Keyis required. Use the same key for the same intent and a new key for a new intent. The key has at most 128 characters and cannot contain:. We recommend a UUID.
The response returns the id of the ledger transaction and the resulting virtual balance:
{ "transaction_id": "0192a0b1-7c2e-7d3f-8a4b-5c6d7e8f9a0c", "balance": "100.000000" }The balance carries six decimal places, so compare amounts as decimal numbers and not as strings. Compare this balance with your own record in every response. This way you see a drift in the request that causes it, and you do not wait for the scheduled reconciliation run.
A request that you send again with the same key and the same body returns the first response byte for byte, and it applies nothing a second time. If the same key arrives with a different body, the response is 422 idempotency_key_reused and nothing is applied.
To send up to 500 movements in one request, use POST /v1/balance-sync/batch. The items apply independently, and the response carries a separate result for each item.
Error envelope
Every error response has the same body:
{
"error": "would_overdraw",
"message": "...",
"details": null,
"request_id": "...",
"source": "...",
"ts": "2026-09-26T12:00:00Z"
}Branch on the error value. The Error codes page lists all the codes. Quote the request_id and source values in a support request. request_id also arrives in the X-Request-Id response header.
All time values are UTC in RFC 3339 format with a Z suffix, in requests and in responses.
Next steps
- For the position endpoints and all the schemas, read the API reference.
- To receive events, read the Webhook guide.
- To show the markets on your own page with the widget, read the Widget guide.
- To get live access, read the Go-live checklist.