Appearance
Developers — quick start
This section is for Nextcloud app developers who want their app to appear inside TeamHub — as a tab, a widget, or both.
Two integration types
TeamHub supports two integration types. They are registered separately — if your app wants both a tab and a widget, you register twice with the same app_id but different integration_type.
| Type | What it is | Renders |
|---|---|---|
menu_item | A tab in the team's tab bar | An iframe at the URL you provide |
widget | A draggable cell on the team's home grid | Data returned by your PHP class implementing ITeamHubWidget |
In five minutes (a menu_item integration)
From your app's install or upgrade hook, call the registration endpoint as an admin:
http
POST /apps/teamhub/api/v1/ext/integrations/register
Content-Type: application/json
{
"app_id": "mywiki",
"integration_type": "menu_item",
"title": "Team Wiki",
"description": "Your team's collaborative wiki",
"icon": "/apps/mywiki/img/app.svg",
"iframe_url": "/apps/mywiki/team-view"
}Response:
json
{ "registry_id": "mywiki:menu_item", "..." }Your integration is registered and available to all teams. It won't appear anywhere yet — a team admin must enable it per team through Manage team → Integrations. When enabled, TeamHub loads your iframe_url in an iframe with ?teamId={teamId} appended.
In five minutes (a widget integration)
A widget is a PHP class your app ships that implements OCA\TeamHub\Integration\ITeamHubWidget. TeamHub calls into it to fetch the widget's data; you don't host an HTTP endpoint of your own.
http
POST /apps/teamhub/api/v1/ext/integrations/register
Content-Type: application/json
{
"app_id": "mywiki",
"integration_type": "widget",
"title": "Wiki Updates",
"icon": "/apps/mywiki/img/app.svg",
"php_class": "OCA\\MyWiki\\TeamHub\\WikiUpdatesWidget"
}The class must implement ITeamHubWidget and provide a fetch(string $teamId, string $userId): array method returning items and optional actions.
What TeamHub gives you
| Channel | What it is |
|---|---|
| Tab (menu_item) | An iframe in the team view filling the content area. |
| Widget | A grid cell rendered from your PHP class's return value. |
| Team context | Every iframe receives ?teamId={teamId}. Widget fetch() receives teamId and userId as arguments. |
| Single sign-on | The iframe loads within the user's Nextcloud session — no separate auth. |
What TeamHub doesn't give you
- No way to post into the team's message stream from your iframe (yet).
- No event bus from TeamHub to your iframe — use standard
postMessageif you need to talk to the parent. - No access to TeamHub's own data (audit log, widget layout, messages) — your app reads its own data, scoped by the
teamIdyou receive.
Security model
TeamHub is not a security boundary for your app. You are responsible for:
- Verifying the user is authenticated — Nextcloud's session does this for normal controllers.
- Verifying the user is a member of the team identified by
teamId. Don't trustteamIdfrom the URL — verify it. - Authorising whatever your app does with the team's data.
For widgets, the fetch() method's $userId is the authenticated Nextcloud user; you can use it directly. For menu_item iframes, verify teamId against the user's circle memberships through Nextcloud Teams' API.
Next steps
- Integration registry → — lifecycle, when to register and unregister, idempotency.
- Widget API → — the
ITeamHubWidgetinterface, fetch contract, return shape. - Menu items → — tab registration, iframe URL constraints, the
teamIdparameter. - API reference → — full endpoint list with request/response shapes.