---
title: "Say who an external account is"
method: POST
path: "/v1/admin/source-connections/{id}/principals/link"
tags: ["Source Plane"]
---

# Say who an external account is

`POST /v1/admin/source-connections/{id}/principals/link`

## Request

- Base URL: `https://brain.inite.ai`
- URL: `https://brain.inite.ai/v1/admin/source-connections/{id}/principals/link`
- Auth: HTTP bearer

Binds one external account to a brain user, so that user holds the `team:` tags of every group the account is in — or unbinds it (`userId: null`), which takes those tags back. A membership edit is an access-control edit: it moves the tenant’s epoch, and the change is in force on the next request. Source plane operator surface (docs/roadmap/raw-evidence-sources-2026-09.md) — answers a bare 404 until `SOURCE_PLANE_ENABLED=1`.

Required scope: `brain:admin`.

## Path parameters

- `id` string, required

## Request body

- SourcePrincipalLinkRequest
  - `externalId` string, required
  - `userId` string, nullable, required

## Response `201`

The mirror after the edit.

- SourcePrincipalsResponse
  - `epoch` integer, required
  - `identities` object[], required
    - `displayName` string, nullable, required
    - `email` string, nullable, required
    - `externalId` string, required
    - `handle` string, nullable, required
    - `linkedBy` string, nullable, required
    - `userId` string, nullable, required
  - `tuples` object[], required
    - `object` string, required
    - `recordedAt` string, required
    - `revokedAt` string, nullable, required
    - `source` string, required
    - `subject` string, required

## Other responses

- `400`: Validation failed.
- `401`: Missing or unknown bearer key.
- `403`: The key lacks the required scope.
- `404`: No such resource in this tenant.

---

[API](https://skmtc.dev/inite/apis/inite-brain-platform-api.md) · [All operations](https://skmtc.dev/inite/apis/inite-brain-platform-api/llms.txt) · [OpenAPI document](https://skmtc.dev/inite/apis/inite-brain-platform-api/revisions/c7c3eb5e304b?raw)
