Access Control

Who can do what, and how to grant it.

Penny’s access model has two kinds of principal — Users (people) and Applications (machine-to-machine clients). Each principal holds permissions, either directly or through roles. A role is a reusable bundle of permissions; it is not a principal and cannot authenticate.

Permissions

A permission is a resource + action pair:

A permission
{
"resource": "account",
"action": "read"
}

Every permission you grant is scoped to your own business.

Resource is one of:

AreaResources
Businessbusiness, sub_business, business_entity, business_defaults, program
Accessuser, role, permission, application, verification
Bankingaccount, ledger, transaction, statement
Issuingcard, cardholder, card_product, bin, spend_control
Billingfee
Platformtask, approval, document, documentation, analytics, notification_endpoint, notification_event, notification_decision_exchange
Simulationsimulation
Wildcard* — every client resource listed above

Action is one of:

ActionGrants
readRetrieve a single resource.
listList resources.
createCreate a resource.
updateChange a resource, including activating, deactivating, and attaching or detaching related objects.
deleteDelete, archive, or terminate a resource.
executeRun an operation, such as a simulation.
revealDisclose a sensitive value, such as a card’s full payment details.
act_asCall Penny on behalf of another business. Penny grants this for multi-business access; you cannot assign it yourself.
*Every action available to you on the resource, except reveal and act_as.

reveal and act_as are never included in a wildcard. Grant them explicitly, and only to the principals that need them.

Each endpoint in the API reference lists the permission it requires.

You can grant a permission — directly, or by adding it to a role — only if you hold it yourself. A request that grants a permission you do not hold fails with 422 Unprocessable Entity.

Roles

A role bundles permissions so you can assign a named set instead of managing individual grants on each principal. Penny provides two kinds of role:

Role typeID prefixOwnershipWhen to use it
Presetglobal_role_Created and maintained by Penny. You can assign it but cannot change it.A standard access profile, such as an administrator, finance, developer, or read-only role.
Customrole_Created and maintained by your business.A combination of permissions that no preset provides.

Preset and custom roles are assigned in exactly the same way. A preset role grants access only within your own business, the same as a custom role.

Preset roles

Discover the preset roles available to your business rather than hardcoding a list. Names and permission sets can change as Penny adds presets.

GET /access/roles/global
GET /access/roles/global/{role_id}

Inspect a preset’s permissions, then assign its role_id to a user or application.

Custom roles

Create a custom role with POST /access/roles/:

POST /access/roles/
{
"name": "Finance auditor",
"description": "Allows finance staff to review transactions and ledger entries.",
"permissions": [
{ "resource": "transaction", "action": "read" },
{ "resource": "transaction", "action": "list" },
{ "resource": "ledger", "action": "list" }
]
}

Use a preset role when it matches the job function. Create a custom role when you need a stable combination that no preset provides, and use direct permissions only for narrow exceptions.

Assigning access to users and applications

Users and applications can hold both directly granted permissions and a set of role_ids. Their effective access is the union of both.

PrincipalMaximum roles
Application10
User5

role_ids accepts both preset (global_role_…) and custom (role_…) role IDs.

Setting the full set

  • POST on a user or application sets its initial permissions and role_ids.
  • PATCH on a user, application, or role replaces the whole permissions set (and, for users and applications, the whole role_ids set) with what you send. It does not merge. Send an empty list to remove everything; omit the field to leave it unchanged.

Because PATCH replaces the set, two concurrent updates can overwrite each other, and adding one permission requires sending the full list.

Adding or removing one grant

To add or remove a single role or permission without sending the full set, use the incremental endpoints:

POST /access/applications/{application_id}/roles/{role_id}
DELETE /access/applications/{application_id}/roles/{role_id}
POST /access/applications/{application_id}/permissions/{resource}/{action}
DELETE /access/applications/{application_id}/permissions/{resource}/{action}

The same endpoints exist under /access/users/{user_id}/.... Custom roles support incremental permission changes too:

POST /access/roles/{role_id}/permissions/{resource}/{action}
DELETE /access/roles/{role_id}/permissions/{resource}/{action}

Attaching a role or permission that is already present, or detaching one that is already absent, succeeds without making a change.

When changes take effect

Changes to roles and permissions can take up to about 5 minutes to apply to requests. Access tokens issued before the change keep working until they expire.

Rotate application secrets

An application’s client_secret is returned once, in the response to POST /access/applications/. Penny does not store it in a retrievable form and does not return it on GET or PATCH. If you lose it, or suspect it was exposed, rotate it:

POST /access/applications/{application_id}/rotate-secret

Rotation returns a new one-time secret. The old secret stops working immediately, so it can no longer be used to request tokens. Access tokens already issued with the old secret stay valid until they expire.