---
title: "Add Application Modules"
method: POST
path: "/api/svc-registry/apps/{app_name}/modules"
tags: ["svc-registry", "svc-registry"]
---

# Add Application Modules

`POST /api/svc-registry/apps/{app_name}/modules`

Idempotently link one or more modules to a primary or companion app.

For each ``moduleId`` this checks whether the
``application -> parent_application -> module`` edge already exists in
FGA and writes only the missing edges. The canonical
``applications.modules`` list is merged (never pruned) to match.

Resolves ``{appName}`` against the durable ``applications`` catalog so
both deployed apps and the FGA-only companions declared via a host's
``fgaOnlyApplications`` block can be targeted by the same endpoint.
The catalog row must already exist — a missing application is rejected
with 404; create one via ``POST /api/svc-registry/apps``.

Authorization (:func:`resolve_module_caller`) accepts either:

* a **service account bound to the target application** — its own
  runtime SA *or* its Terraform SA — exactly like the sharable-entity
  runtime API. Ownership is enforced via
  :func:`_resolve_target_application_for_caller`, so a companion can
  only be extended by its host's runtime/Terraform SA (matched on
  ``runtime_owner_application_id``); a caller bound to a different
  application is rejected with 403.
* a **human ``gcp-developers@gocrisp.com`` member**, authorized for
  any target (the same operator path as ``POST /apps``).

## Path parameters

- `app_name` string, required

## Request body

- AddApplicationModulesRequest — Payload accepted by ``POST /api/svc-registry/apps/{appName}/modules``. ``moduleIds`` is the set of authorization modules to (idempotently) link to the application catalog. Each id is a lowercase slug, matching the ``authorizationModules`` convention used by registration.
  - `moduleIds` string[], nullable
  - `modules` AddApplicationModuleEntry[], nullable
    - `id` string, required
    - `attachments` ApplicationAttachmentDeclaration[], nullable
      - `scope` AttachmentTarget, required — One attachment target in a registration payload. ``kind='account', all=true`` is accepted as wire-compatible sugar for the non-FGA fan-out target ``kind='all_accounts'``. Concrete FGA scopes require either ``id`` or ``ids``.
        - `kind` 'platform' | 'portfolio' | 'account' | 'all_accounts', required
        - `id` string, nullable
        - `ids` string[], nullable
        - `all` boolean
      - `modules` string[]
      - `source` 'registration' | 'operator' | 'dynamic'

## Response `200`

Successful Response

- AddApplicationModulesResponse — Result of an idempotent module-addition request. ``modules`` is the full module list on the application catalog after the operation. ``added`` and ``alreadyPresent`` partition the requested ids by whether a new ``application -> module`` edge was written or already existed in FGA.
  - `applicationId` string, required
  - `modules` string[]
  - `added` string[]
  - `alreadyPresent` string[]

## Other responses

- `422` — Validation Error

---

[API](https://skmtc.dev/gocrisp/apis/crisp-app-dock.md) · [All operations](https://skmtc.dev/gocrisp/apis/crisp-app-dock/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/gocrisp/crisp-app-dock/revisions/e56bd3c1a9db/schema)
