Skip to main content

Connected Apps

Connected apps let one project call another project's hooks from its code. The project that is called is the app; the project that calls it is the caller. The app decides which of its hooks can be called (its actions) and which projects may call each one, with the same roles you already use in Access Control.

There are no tokens or connections to manage: the app's managers give the calling project a role, and the caller's code runs the action with one function.

from abstra.apps import run_app_action

invoice = run_app_action(
project_id="2c051024-fd14-441b-9d11-a6bc7d1c94c0", # the app
action="create-invoice",
parameters={"customer_id": "c-42", "amount": 199.9},
)
Availability

Connected apps is being rolled out by organization. If you don't see Connected apps in your project's sidebar, contact support to enable it. A project can be given roles on apps of its own organization.

How it works​

  1. The app declares actions. An action is a hook that declares an api_schema: a description, the JSON Schema of the parameters it accepts and, optionally, of what it answers. See Declaring actions.
  2. The app gives the caller access. Public hooks can be called by any project, as they can be called by anyone over HTTP. For a private hook, the app's managers give the calling project one of the roles the hook requires.
  3. The caller runs the action. run_app_action validates the parameters against the action's schema, checks the caller's access, runs the hook in the app's production deploy and returns the hook's answer.

Giving a project access​

In the app project's console:

  1. Open Access Control → Roles and pick (or create) the role the hook requires.
  2. In Who has this role, search for the calling project's name. Projects appear under Projects.
  3. Select it. The project shows as a chip on the role, and you can remove it the same way.

The roles a project holds work exactly like a person's: the project can run every private action whose roles include one of them. To make a hook require a role, set it to private with that role in Access Control → Stages (if your hooks aren't listed there, contact support to enable hook access control).

You can only give roles to projects of the app's own organization.

Seeing what a project can call​

In the calling project's console, Connected apps lists the apps the project holds a role on. Open an app to see the actions this project may run; open an action to see its parameters, its answer and a code snippet to call it.

From code, the same information comes from list_connected_apps, list_app_actions and describe_app_action (see the SDK reference). Smart Chat and MCP clients have matching tools; Smart Chat always asks you before running an action.

Calling an action​

from abstra.apps import AppActionError, run_app_action

try:
quote = run_app_action(
BILLING_APP_ID,
"quote-order",
{"customer": {"name": "Ana", "email": "ana@example.com"}, "items": [...], "shipping": {"method": "pickup"}},
)
except AppActionError as error:
print(error.status, error.code, error.details)
  • The call runs the app's production deploy, from the editor too: test with care when an action writes data.
  • It returns the hook's response body, parsed as JSON when it is JSON.
  • It raises AppActionError when the call is refused, or when the hook answers with an error status (400 or above). See Errors.

What the app's hook receives​

The hook runs as if it received a POST with the parameters as its JSON body, so get_request() works as usual. It also receives who is calling:

HeaderValue
x-abstra-caller-project-idThe calling project's id
x-abstra-caller-project-nameThe calling project's name
x-abstra-caller-organization-idThe calling project's organization
x-abstra-call-depthHow many cross-project calls led here (1 for a direct call)

These headers are only set by Abstra: they are removed from any plain HTTP request to the hook, so the hook can trust them.

import abstra.hooks as ah

body, query, headers = ah.get_request()
caller = headers.get("x-abstra-caller-project-name")

Limits​

LimitValue
Calls from one project to one app120 per minute
Calls from one project to one app running at the same time10
Chain of calls (A calls B, which calls C…)8 deep

Past a limit, run_app_action raises AppActionError with status 429 (rate_limited) or 508 (call_depth_exceeded). The executions count against the app's organization, like any hook execution.