API overview
Base URLs: https://api.payability.com/actionstools in production; the ApiUrl output of the actionstools-stage stack on
stage. Swagger UI for the flask-restx namespaces is served at the base URL. All paths below
are relative to it and end with a trailing slash unless shown otherwise.
Authentication
Two schemes, both implemented in pyb_flask_utils.auth:
| Decorator | Accepts | Used by |
|---|---|---|
|
|
Every |
|
The JWT above, or |
|
A valid JWT gives the view login_id (email) and login_key (user uuid). Authentication
failures return 400, not 401, on purpose: a 401 logs IA and service-desk users out.
Context headers
| Header | Maps to | Meaning |
|---|---|---|
|
|
The entity the item belongs to — usually a supplier key, or a task/note uuid for comments. |
|
|
Kind of target, e.g. |
|
|
Overridden by the JWT’s |
|
|
Item sub-type. |
|
|
SaaS instance; Payability is |
Defined in config.HEADERS; parsed by pyb_flask_utils.rest.common.Helper.
Response envelope
Every JSON response has the same shape (pyb_flask_utils.rest.response.prepare_json_response):
{
"status_code": 200,
"data": {
"uuid": "3247c9d9-b181-40e0-893f-7d856fb23e47",
"target_uuid": "5298d876-da14-46ce-86d6-2dfd0d81ba65",
"type": "note",
"body": "<p>Called the supplier</p>",
"is_pinned": false,
"created_at": "2026-10-28 09:54:27.123456"
},
"meta": {
"message": "object has been successfully created"
}
}
Collections put a list in data and pagination in meta:
{
"status_code": 200,
"data": [
{"uuid": "3247c9d9-b181-40e0-893f-7d856fb23e47", "type": "note", "body": "<p>First</p>"},
{"uuid": "9f1b2c3d-0000-4000-8000-000000000002", "type": "note", "body": "<p>Second</p>"}
],
"meta": {
"count": 7,
"last": {
"target_uuid": "5298d876-da14-46ce-86d6-2dfd0d81ba65",
"uuid": "9f1b2c3d-0000-4000-8000-000000000002",
"updated_at": "2026-10-27 18:02:11.000000"
}
}
}
Errors keep the envelope; meta.errors lists {type, message} and status_code repeats the
HTTP status:
{
"status_code": 404,
"data": null,
"meta": {
"errors": [
{"type": "ResourceNotFound", "message": "Cannot find any items"}
]
}
}
Common error types: ResourceNotFound (404), Unauthorized (400), Unknown (500),
DataValidationException / BadRequest (400), AccessDenied (403).
Pagination, filtering and ordering
-
?limit=<n>— page size (DynamoDBLimit, so a filtered page may hold fewer items). -
?last=<json>— passmeta.lastfrom the previous page verbatim (URL-encoded JSON). Nometa.lastmeans no further pages. -
?q={"filters":[{"name":"status","op":"in","val":["new","in-progr"]}]}— filters on list endpoints that support them (tasks, settings). Operators:eq,ne,in,lt,gt(and the boto3 condition operators supported byFilterHelper). -
?order_by={"field":"created_at","direction":"desc"}— picks a matching index where one exists.
Route catalog
| Method | Path | Page |
|---|---|---|
GET, POST |
|
|
GET, PUT, PATCH, DELETE |
|
|
GET |
|
|
POST |
|
|
POST |
|
|
GET, POST, PATCH, DELETE |
|
|
GET, PUT, DELETE |
|
|
POST |
|
|
POST |
|
|
GET |
|
|
GET, POST |
|
|
PATCH, DELETE |
|
|
GET, POST |
|
|
GET |
|
|
DELETE |
|
|
GET, POST |
|
|
GET, PUT, DELETE |
|
|
GET |
|
|
GET, POST |
|
|
DELETE |
|
|
GET, POST, PATCH |
|
|
PATCH |
|
|
GET |
|
|
GET |
|
|
GET |
|
Creates missing tables from |
In production /files/ and /settings/ are also registered without the /actionstools
prefix ("temporary path workaround" in create_app).
|
|