Running a firm

.md

The endpoints behind the Propper app, which puts the admin panel on a phone.

The admin endpoints are the admin panel, for the people who run a propfirm and for our own staff. They are part of the app API and take a user token, never an API key, because every one of them answers the question of what this particular person may see and do.

They live under /v1/admin, beside /v1/me, and they are being added screen by screen. What is here today is the frame the app draws around those screens.

Who may use them

A token for the app admin, holding admin:read and, for anything that changes something, admin:write. Those two scopes are only granted to a sign-in with "app": "admin". A token for Propper Mail that asks for them signs in without them, and answers 403 insufficient_scope here.

The account has to help run the environment, by the same test as the admin panel on the web: the firm's owner, our own staff, or somebody whose role grants at least one permission. Anybody else is refused at sign-in already, with 403 admin_access_required, so an app never ends up holding a token for a panel it cannot open.

Which firm

A request acts in the environment its account belongs to, or in the one named by the Propper-Workspace header, as everywhere else.

Our own staff belong to the platform. An endpoint that works on one firm, such as your sidebar, answers them 400 workspace_required until they name one. That is on purpose: without a firm, staff can see the rows of every firm at once, and a forgotten header should be an error rather than a list of everybody's traders.

An endpoint of the platform itself answers anybody else 403 platform_required.

Permissions

Each endpoint asks for the permission its screen on the web asks for, worked out the same way: an owner holds everything, and a permission that implies another counts as both. Its page names it at the top and in its errors. Without it the answer is 403 forbidden, with required_permission naming what was missing:

{
    "error": {
        "type": "permission_error",
        "code": "forbidden",
        "message": "Your role does not allow this.",
        "required_permission": "view_payouts"
    },
    "meta": { "request_id": "req_01kz4bkr1aj1gv63d8fv3133ey" }
}

Draw the app from the profile, which answers every permission there is, and expect this anyway when a role changes between the call and the tap.

Everything is in the activity log

Every screen read in a firm is written to that firm's activity log, as a page viewed on the web is, with source set to app. A firm's audit trail should not go quiet because somebody read it on a phone. Asking for the same page again within thirty seconds is one entry, so pulling to refresh does not flood it. The profile is not logged: an app asks for it every time it starts, which says nothing about what anybody looked at.