Skip to content

apps ​

← All modules

11 endpoints.

GET /api/v1/apps ​

List Apps

The catalog, annotated with whether each app is installed on this site, plus the site-wide show_not_allowed display setting.

200 — Successful Response

json
{}

POST /api/v1/apps/show-not-allowed ​

Set Show Not Allowed

Show or hide the apps this site isn't allowed to install (superuser only).

Site-wide and stored in the database, so every user of this site sees the same library — unlike a per-browser preference. Hiding them only affects what the Apps Library lists; the underlying refusal to install them (:func:app.core.apps.forbidden_apps) is unchanged.

Request body

json
{
  "properties": {
    "show": {
      "type": "boolean",
      "title": "Show"
    }
  },
  "type": "object",
  "required": [
    "show"
  ],
  "title": "ShowNotAllowedIn"
}

200 — Successful Response

json
{}

422 — Validation Error

json
{
  "properties": {
    "detail": {
      "items": {
        "properties": {
          "loc": {
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ]
            },
            "type": "array",
            "title": "Location"
          },
          "msg": {
            "type": "string",
            "title": "Message"
          },
          "type": {
            "type": "string",
            "title": "Error Type"
          }
        },
        "type": "object",
        "required": [
          "loc",
          "msg",
          "type"
        ],
        "title": "ValidationError"
      },
      "type": "array",
      "title": "Detail"
    }
  },
  "type": "object",
  "title": "HTTPValidationError"
}

GET /api/v1/apps/setup-status ​

Setup Status

Setup-completeness for the site's basic-trading apps, from their registered :mod:app.core.setup_checks.

Membership is EVERY app this site has installed, in its own app order (2026-08-21, owner: "put all apps on setup in order of their left menu"). It was cut down to a BASIC_SETUP_APPS allow-list on 2026-08-18 — the basics for trading only — and that constant is gone with this change rather than left behind unused; the registry in :mod:app.core.setup_checks still carries every app's checks, which is what made restoring the full list a one-line filter change. An installed app with no registered checks appears with total: 0 and says so, rather than being hidden.

Each check is run as run(db, site) and any exception counts as "not done" (and is logged — a check that throws on every request is a bug in the check, not a finding about the site). An installed app with no registered checks is reported with total: 0 — the caller should show "no setup checks defined yet" rather than inferring 0% or 100%.

Each check comes back as a full wizard step (see :func:_step_payload): why it matters, the value it currently resolves to, and — where the setting is one this page can write — the inputs to set it, prefilled and with secrets redacted. PUT /apps/{slug}/setup/{step} saves them back. Every app in APP_CATALOG carries checks since 2026-08-11, so that state now means "a new app hasn't registered its checks yet".

One flat list, in the site's own get_app_order — the SAME order, from the same source, that the Apps Library lays its cards out in and that the left menu follows. It was grouped into category sections until 2026-08-18 (owner: "sort in order of app library"), which quietly reordered the page against the library it mirrors: a drag-to-reorder in the library moved a card there and nothing here, because the category buckets were applied on top of that order. Each app still reports its category_name, which the caller shows as a badge — the way the Apps Library card shows it — rather than as a heading to sort under.

Within a card the STEPS follow the left menu too (2026-08-21, owner: "if left menu is reordered, then the setup must reorder accordingly"): each step is ranked by where the menu puts the screen it points at, within that app's OWN section (:func:_menu_rank), and the card's sections come out in that order. Reordering the menu reorders this page on the next load. A step whose destination the app's section doesn't carry — another app's screen, or a hub grid reached by absolute url — sorts last, and the registry's own order is what survives as the tiebreak between steps the menu ranks equally.

Every step also carries the CONSOLE it belongs to — section, one of the drop-downs under Superadmin, resolved from the menu by where the step's destination screen lives (:func:_console_sections, 2026-08-23, owner: "split into 3 tabs for each of the drop downs under superadmin"). The sections list at the top level names them, in menu order, and default_section is the one this page itself sits in — where a step whose destination no console owns is filed. The apps and their counters are unchanged by this: the response is still ONE list, and the tabs are a view of it, so a caller that ignores sections renders exactly the page it did before (which is what the sidebar's progress widget does).

ONE app is moved out of that order: system is pinned FIRST (2026-08-21, owner: "system must be first, then the rest of the apps"). get_app_order pins the platform apps LAST for the library and the left menu, which is right there and wrong here — System carries the organization, the administrator, outgoing SMTP and the site's registry facts, i.e. the steps that come before anything else is worth configuring, so on the setup page they were at the bottom. This is a single explicit pin, not a re-sort: every other app keeps the library's order relative to the others, so a drag-to-reorder there still moves this page.

200 — Successful Response

json
{}

PUT /api/v1/apps/{slug}/setup/{step} ​

Save Setup Step

Store one wizard step's inputs and report the step back, re-checked.

The write goes to whichever service already owns that setting (see :mod:app.core.setup_checks) — this endpoint owns no storage of its own, so a value saved here reads back identically on the settings page or grid that edits the same thing. Superuser-only, like every other mutation in this module: these are site-wide credentials and platform switches, not personal preferences.

Parameters

NameInRequiredTypeDescription
slugpathyesstring
steppathyesstring

Request body

json
{
  "properties": {
    "values": {
      "additionalProperties": true,
      "type": "object",
      "title": "Values"
    }
  },
  "type": "object",
  "title": "SetupStepIn"
}

200 — Successful Response

json
{}

422 — Validation Error

json
{
  "properties": {
    "detail": {
      "items": {
        "properties": {
          "loc": {
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ]
            },
            "type": "array",
            "title": "Location"
          },
          "msg": {
            "type": "string",
            "title": "Message"
          },
          "type": {
            "type": "string",
            "title": "Error Type"
          }
        },
        "type": "object",
        "required": [
          "loc",
          "msg",
          "type"
        ],
        "title": "ValidationError"
      },
      "type": "array",
      "title": "Detail"
    }
  },
  "type": "object",
  "title": "HTTPValidationError"
}

POST /api/v1/apps/{slug}/install ​

Install App

Parameters

NameInRequiredTypeDescription
slugpathyesstring

200 — Successful Response

json
{}

422 — Validation Error

json
{
  "properties": {
    "detail": {
      "items": {
        "properties": {
          "loc": {
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ]
            },
            "type": "array",
            "title": "Location"
          },
          "msg": {
            "type": "string",
            "title": "Message"
          },
          "type": {
            "type": "string",
            "title": "Error Type"
          }
        },
        "type": "object",
        "required": [
          "loc",
          "msg",
          "type"
        ],
        "title": "ValidationError"
      },
      "type": "array",
      "title": "Detail"
    }
  },
  "type": "object",
  "title": "HTTPValidationError"
}

POST /api/v1/apps/{slug}/uninstall ​

Uninstall App

Parameters

NameInRequiredTypeDescription
slugpathyesstring

200 — Successful Response

json
{}

422 — Validation Error

json
{
  "properties": {
    "detail": {
      "items": {
        "properties": {
          "loc": {
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ]
            },
            "type": "array",
            "title": "Location"
          },
          "msg": {
            "type": "string",
            "title": "Message"
          },
          "type": {
            "type": "string",
            "title": "Error Type"
          }
        },
        "type": "object",
        "required": [
          "loc",
          "msg",
          "type"
        ],
        "title": "ValidationError"
      },
      "type": "array",
      "title": "Detail"
    }
  },
  "type": "object",
  "title": "HTTPValidationError"
}

POST /api/v1/apps/{slug}/custom ​

Set App Custom

Link (or unlink) an app to the one site it was custom-built for (superuser only). Platform-wide — see :func:app.core.apps.set_custom_app.

Parameters

NameInRequiredTypeDescription
slugpathyesstring

Request body

json
{
  "properties": {
    "site": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "title": "Site"
    },
    "instance": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "title": "Site"
    }
  },
  "type": "object",
  "title": "CustomAppIn"
}

200 — Successful Response

json
{}

422 — Validation Error

json
{
  "properties": {
    "detail": {
      "items": {
        "properties": {
          "loc": {
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ]
            },
            "type": "array",
            "title": "Location"
          },
          "msg": {
            "type": "string",
            "title": "Message"
          },
          "type": {
            "type": "string",
            "title": "Error Type"
          }
        },
        "type": "object",
        "required": [
          "loc",
          "msg",
          "type"
        ],
        "title": "ValidationError"
      },
      "type": "array",
      "title": "Detail"
    }
  },
  "type": "object",
  "title": "HTTPValidationError"
}

GET /api/v1/apps/custom-apps ​

List Custom Apps

Every custom-app module Labib has built for THIS site (see the create_custom_app MCP tool and app/core/custom_app_runtime.py) — powers the "My Apps" index page. Each module is a real, seeded ErpModule row like any other grid, and the custom- slug prefix IS the index. The definitions, tables and rows all live in the site's own schema, so this only ever sees the current site's own apps.

200 — Successful Response

json
{}

GET /api/v1/apps/hub-sync ​

Hub Sync Status

What the hub believes about every site's left menu: the canonical revision, which targets are on it, and which are behind and why.

Parameters

NameInRequiredTypeDescription
refresh_estatequerynoboolean

200 — Successful Response

json
{
  "type": "object",
  "additionalProperties": true,
  "title": "Response Hub Sync Status Api V1 Apps Hub Sync Get"
}

422 — Validation Error

json
{
  "properties": {
    "detail": {
      "items": {
        "properties": {
          "loc": {
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ]
            },
            "type": "array",
            "title": "Location"
          },
          "msg": {
            "type": "string",
            "title": "Message"
          },
          "type": {
            "type": "string",
            "title": "Error Type"
          }
        },
        "type": "object",
        "required": [
          "loc",
          "msg",
          "type"
        ],
        "title": "ValidationError"
      },
      "type": "array",
      "title": "Detail"
    }
  },
  "type": "object",
  "title": "HTTPValidationError"
}

POST /api/v1/apps/hub-sync/run ​

Hub Sync Run

Push the canonical left menu to the estate now, and wait for the answer.

Unlike the automatic push behind a menu edit, this one is synchronous: the caller asked to see the result, and the interesting part of that result is which boxes did NOT answer. Expect it to take a few seconds — four SSH round-trips plus ~20 local databases.

Request body

json
{
  "properties": {
    "dry_run": {
      "type": "boolean",
      "title": "Dry Run",
      "default": false
    },
    "force": {
      "type": "boolean",
      "title": "Force",
      "default": false
    },
    "refresh_estate": {
      "type": "boolean",
      "title": "Refresh Estate",
      "default": false
    },
    "targets": {
      "anyOf": [
        {
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        {
          "type": "null"
        }
      ],
      "title": "Targets"
    },
    "allow_removals": {
      "anyOf": [
        {
          "type": "boolean"
        },
        {
          "type": "null"
        }
      ],
      "title": "Allow Removals"
    }
  },
  "type": "object",
  "title": "HubSyncRunIn"
}

200 — Successful Response

json
{
  "additionalProperties": true,
  "type": "object",
  "title": "Response Hub Sync Run Api V1 Apps Hub Sync Run Post"
}

422 — Validation Error

json
{
  "properties": {
    "detail": {
      "items": {
        "properties": {
          "loc": {
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ]
            },
            "type": "array",
            "title": "Location"
          },
          "msg": {
            "type": "string",
            "title": "Message"
          },
          "type": {
            "type": "string",
            "title": "Error Type"
          }
        },
        "type": "object",
        "required": [
          "loc",
          "msg",
          "type"
        ],
        "title": "ValidationError"
      },
      "type": "array",
      "title": "Detail"
    }
  },
  "type": "object",
  "title": "HTTPValidationError"
}

POST /api/v1/apps/reorder ​

Reorder Apps

Persist a new Apps Library order for the active site (superuser only).

Saves the order to the site config and mirrors it onto this site's top-level menu groups (by app_slug) so the left sidebar is sorted to match — the requirement that the left menu follows the app order.

Request body

json
{
  "properties": {
    "ordered_slugs": {
      "items": {
        "type": "string"
      },
      "type": "array",
      "title": "Ordered Slugs"
    }
  },
  "type": "object",
  "title": "ReorderAppsIn"
}

200 — Successful Response

json
{}

422 — Validation Error

json
{
  "properties": {
    "detail": {
      "items": {
        "properties": {
          "loc": {
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ]
            },
            "type": "array",
            "title": "Location"
          },
          "msg": {
            "type": "string",
            "title": "Message"
          },
          "type": {
            "type": "string",
            "title": "Error Type"
          }
        },
        "type": "object",
        "required": [
          "loc",
          "msg",
          "type"
        ],
        "title": "ValidationError"
      },
      "type": "array",
      "title": "Detail"
    }
  },
  "type": "object",
  "title": "HTTPValidationError"
}

Lubb One Documentation