# Link meeting calendar event

Link a recorded meeting to its calendar event, or pass event_id: null to unlink it. Only the meeting host can change the link; an event with another recording cannot be reused.

POST https://api.brigg.app/v1/operations/meetings.LinkMeetingCalendarEvent

## Access & visibility

Allow `meetings.LinkMeetingCalendarEvent` on your API key. Resource write permissions: `core:Meeting`, `core:MeetingNote`.

**Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](https://developer.brigg.app/authentication#member-delegation). The key supplies permissions; the member selects whose data is used.

The selected member must be active and approved by the credential. This selects whose private data is used; the credential supplies permissions. Private ownership and project boundaries still apply.

[Set up authentication](https://developer.brigg.app/authentication) · [Choose permissions](https://developer.brigg.app/permissions)

## Request fields

Send a JSON object with the following fields. Required fields must be included; omit optional fields you do not need.
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | Yes | Recorded Meeting id from ListMeetings. The acting member must be its host. At least 1 character. At most 128 characters. |
| `event_id` | string or null | Yes | Brigg CalendarEvent id visible to this same member, from ListCalendarEvents. This is neither the meeting ID nor the provider's event ID. Null explicitly unlinks. |

## Linking also reconciles meeting details

Choose the recording from [List meetings](https://developer.brigg.app/reference/meetings/ListMeetings) and a calendar event visible to the same host from [List calendar events](https://developer.brigg.app/reference/meetings/ListCalendarEvents). Linking updates the meeting title and invitation details from that event and resolves its attendee contacts. It does not change the recording's visibility or create or edit the provider's calendar event.

If the event already has a prepared meeting without a recording, Brigg merges eligible preparation and the acting member's note where the recording has none, then removes the prepared meeting. Existing recording content is not overwritten by that preparation, and private preparation is not made workspace-visible. An event with another recording is refused.

To unlink, send event_id=null. This removes the calendar association and invitation UID, but keeps the recording, its content and detected conference URL; it does not undo an earlier merge. Read [Get meeting](https://developer.brigg.app/reference/meetings/GetMeeting) after either action.

## Response

Returns **200 OK** with a JSON body.
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `ok` | boolean | Yes | Whether the action completed successfully. |
| `meeting_id` | string | Yes | The request's id; the recording keeps this identity. |
| `calendar_event_id` | string or null | Yes | The linked event_id, or null after unlinking. |
| `absorbed_meeting_id` | string or null | Yes | ID of a prepared, unrecorded meeting merged into this recording and removed, or null when none was merged. Stop using an absorbed ID; meeting_id is the surviving record. |

## Errors & retries

Set `BRIGG_REQUEST_ID` once for each logical action. The samples send it as `Idempotency-Key`. Reuse the same value and body on retries, including after a timeout; a missing response does not prove the action failed.

For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](https://developer.brigg.app/http#errors) and [safe retries and limits](https://developer.brigg.app/reliability).

| HTTP status | Code | What to do |
| --- | --- | --- |
| 400 | `invalid_json` | Send a JSON object with Content-Type: application/json. |
| 400 | `invalid_input` | Check the request fields and types. Supply a stable Idempotency-Key containing 1–200 characters. |
| 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. |
| 403 | `forbidden` | Check the key’s operation and resource grants. Supply Brigg-Act-As with a member authorized by the key’s delegation grant. The selected member must be active and approved by the credential. This selects whose private data is used; the credential supplies permissions. Private ownership and project boundaries still apply. |
| 404 | `not_found` | The requested operation or resource is not available to this credential. |
| 429 | `rate_limited` | Wait for Retry-After before retrying. Reuse the original Idempotency-Key. |
| 403 | `not_host` | Delegate to the host of the selected recording; knowing its ID or being an administrator does not replace this host check. |
| 404 | `meeting_not_found` | Select a visible Meeting from ListMeetings. |
| 404 | `event_not_found` | Select a Brigg CalendarEvent visible to the same acting member, not a provider event ID. |
| 409 | `event_taken` | The calendar event already has another recording. Choose another event or review the existing recording; an unrecorded prepared meeting can instead be absorbed. |

## Next steps

- [List meetings](https://developer.brigg.app/reference/meetings/ListMeetings)
- [List calendar events](https://developer.brigg.app/reference/meetings/ListCalendarEvents)
- [Get meeting](https://developer.brigg.app/reference/meetings/GetMeeting)

[Download OpenAPI](https://developer.brigg.app/openapi.json) · [Versioning & retirement](https://developer.brigg.app/versioning)

## Examples

### Link the recording

The response repeats the two distinct identities from the request.
#### cURL


```sh
curl 'https://api.brigg.app/v1/operations/meetings.LinkMeetingCalendarEvent' \
  -H "Authorization: Bearer $BRIGG_API_KEY" \
  -H 'Content-Type: application/json' \
  -H "Brigg-Act-As: $BRIGG_ACT_AS" \
  -H "Idempotency-Key: $BRIGG_REQUEST_ID" \
  --data-raw '{
  "id": "e_meeting_kickoff",
  "event_id": "e_calendar_kickoff"
}'
```

#### TypeScript


```typescript
const actAs = process.env.BRIGG_ACT_AS;
if (!actAs) throw new Error("Set BRIGG_ACT_AS to an approved member account ID.");

const requestId = process.env.BRIGG_REQUEST_ID;
if (!requestId) throw new Error("Set BRIGG_REQUEST_ID once per action and reuse it on retries.");

const response = await fetch("https://api.brigg.app/v1/operations/meetings.LinkMeetingCalendarEvent", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.BRIGG_API_KEY}`,
    "Content-Type": "application/json",
    "Brigg-Act-As": actAs,
    "Idempotency-Key": requestId, // Create once per action; reuse on retries.
  },
  body: JSON.stringify({
    "id": "e_meeting_kickoff",
    "event_id": "e_calendar_kickoff"
  }),
});
const result = await response.json();
if (!response.ok) throw new Error(`${response.status}: ${result.error} — ${result.message}`);
console.log(result);
```

#### Python


```python
import json
import os
from urllib.request import Request, urlopen
from urllib.error import HTTPError

request_id = os.environ["BRIGG_REQUEST_ID"]  # Reuse for retries of this action.
payload = {
  "id": "e_meeting_kickoff",
  "event_id": "e_calendar_kickoff"
}
request = Request(
    "https://api.brigg.app/v1/operations/meetings.LinkMeetingCalendarEvent",
    data=json.dumps(payload).encode("utf-8"),
    headers={
        "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}",
        "Content-Type": "application/json",
        "Brigg-Act-As": os.environ["BRIGG_ACT_AS"],
        "Idempotency-Key": request_id,  # Create once per action; reuse on retries.
    },
    method="POST",
)
try:
    with urlopen(request) as response:
        print(json.load(response))
except HTTPError as error:
    print(error.code, json.load(error))
    raise
```

#### Response example


```json
{
  "ok": true,
  "meeting_id": "e_meeting_kickoff",
  "calendar_event_id": "e_calendar_kickoff",
  "absorbed_meeting_id": null
}
```

### Link and absorb preparation

Use meeting_id from now on; the prepared companion is removed.
#### cURL


```sh
curl 'https://api.brigg.app/v1/operations/meetings.LinkMeetingCalendarEvent' \
  -H "Authorization: Bearer $BRIGG_API_KEY" \
  -H 'Content-Type: application/json' \
  -H "Brigg-Act-As: $BRIGG_ACT_AS" \
  -H "Idempotency-Key: $BRIGG_REQUEST_ID" \
  --data-raw '{
  "id": "e_meeting_kickoff",
  "event_id": "e_calendar_kickoff"
}'
```

#### TypeScript


```typescript
const actAs = process.env.BRIGG_ACT_AS;
if (!actAs) throw new Error("Set BRIGG_ACT_AS to an approved member account ID.");

const requestId = process.env.BRIGG_REQUEST_ID;
if (!requestId) throw new Error("Set BRIGG_REQUEST_ID once per action and reuse it on retries.");

const response = await fetch("https://api.brigg.app/v1/operations/meetings.LinkMeetingCalendarEvent", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.BRIGG_API_KEY}`,
    "Content-Type": "application/json",
    "Brigg-Act-As": actAs,
    "Idempotency-Key": requestId, // Create once per action; reuse on retries.
  },
  body: JSON.stringify({
    "id": "e_meeting_kickoff",
    "event_id": "e_calendar_kickoff"
  }),
});
const result = await response.json();
if (!response.ok) throw new Error(`${response.status}: ${result.error} — ${result.message}`);
console.log(result);
```

#### Python


```python
import json
import os
from urllib.request import Request, urlopen
from urllib.error import HTTPError

request_id = os.environ["BRIGG_REQUEST_ID"]  # Reuse for retries of this action.
payload = {
  "id": "e_meeting_kickoff",
  "event_id": "e_calendar_kickoff"
}
request = Request(
    "https://api.brigg.app/v1/operations/meetings.LinkMeetingCalendarEvent",
    data=json.dumps(payload).encode("utf-8"),
    headers={
        "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}",
        "Content-Type": "application/json",
        "Brigg-Act-As": os.environ["BRIGG_ACT_AS"],
        "Idempotency-Key": request_id,  # Create once per action; reuse on retries.
    },
    method="POST",
)
try:
    with urlopen(request) as response:
        print(json.load(response))
except HTTPError as error:
    print(error.code, json.load(error))
    raise
```

#### Response example


```json
{
  "ok": true,
  "meeting_id": "e_meeting_kickoff",
  "calendar_event_id": "e_calendar_kickoff",
  "absorbed_meeting_id": "e_meeting_prepared"
}
```

### Remove the calendar link

This preserves the recording and does not restore any absorbed companion.
#### cURL


```sh
curl 'https://api.brigg.app/v1/operations/meetings.LinkMeetingCalendarEvent' \
  -H "Authorization: Bearer $BRIGG_API_KEY" \
  -H 'Content-Type: application/json' \
  -H "Brigg-Act-As: $BRIGG_ACT_AS" \
  -H "Idempotency-Key: $BRIGG_REQUEST_ID" \
  --data-raw '{
  "id": "e_meeting_kickoff",
  "event_id": null
}'
```

#### TypeScript


```typescript
const actAs = process.env.BRIGG_ACT_AS;
if (!actAs) throw new Error("Set BRIGG_ACT_AS to an approved member account ID.");

const requestId = process.env.BRIGG_REQUEST_ID;
if (!requestId) throw new Error("Set BRIGG_REQUEST_ID once per action and reuse it on retries.");

const response = await fetch("https://api.brigg.app/v1/operations/meetings.LinkMeetingCalendarEvent", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.BRIGG_API_KEY}`,
    "Content-Type": "application/json",
    "Brigg-Act-As": actAs,
    "Idempotency-Key": requestId, // Create once per action; reuse on retries.
  },
  body: JSON.stringify({
    "id": "e_meeting_kickoff",
    "event_id": null
  }),
});
const result = await response.json();
if (!response.ok) throw new Error(`${response.status}: ${result.error} — ${result.message}`);
console.log(result);
```

#### Python


```python
import json
import os
from urllib.request import Request, urlopen
from urllib.error import HTTPError

request_id = os.environ["BRIGG_REQUEST_ID"]  # Reuse for retries of this action.
payload = {
  "id": "e_meeting_kickoff",
  "event_id": None
}
request = Request(
    "https://api.brigg.app/v1/operations/meetings.LinkMeetingCalendarEvent",
    data=json.dumps(payload).encode("utf-8"),
    headers={
        "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}",
        "Content-Type": "application/json",
        "Brigg-Act-As": os.environ["BRIGG_ACT_AS"],
        "Idempotency-Key": request_id,  # Create once per action; reuse on retries.
    },
    method="POST",
)
try:
    with urlopen(request) as response:
        print(json.load(response))
except HTTPError as error:
    print(error.code, json.load(error))
    raise
```

#### Response example


```json
{
  "ok": true,
  "meeting_id": "e_meeting_kickoff",
  "calendar_event_id": null,
  "absorbed_meeting_id": null
}
```

## JSON schemas


```json-schema-request
{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 128,
      "description": "Recorded Meeting id from ListMeetings. The acting member must be its host."
    },
    "event_id": {
      "anyOf": [
        {
          "type": "string",
          "minLength": 1,
          "description": "Brigg CalendarEvent id visible to this same member, from ListCalendarEvents. This is neither the meeting ID nor the provider's event ID. Null explicitly unlinks."
        },
        {
          "type": "null",
          "description": "Brigg CalendarEvent id visible to this same member, from ListCalendarEvents. This is neither the meeting ID nor the provider's event ID. Null explicitly unlinks."
        }
      ],
      "description": "Brigg CalendarEvent id visible to this same member, from ListCalendarEvents. This is neither the meeting ID nor the provider's event ID. Null explicitly unlinks."
    }
  },
  "required": [
    "id",
    "event_id"
  ],
  "additionalProperties": false,
  "examples": [
    {
      "id": "e_meeting_kickoff",
      "event_id": "e_calendar_kickoff"
    }
  ]
}
```


```json-schema-response
{
  "type": "object",
  "properties": {
    "ok": {
      "type": "boolean",
      "description": "Whether the action completed successfully."
    },
    "meeting_id": {
      "type": "string",
      "description": "The request's id; the recording keeps this identity."
    },
    "calendar_event_id": {
      "type": [
        "string",
        "null"
      ],
      "description": "The linked event_id, or null after unlinking."
    },
    "absorbed_meeting_id": {
      "type": [
        "string",
        "null"
      ],
      "description": "ID of a prepared, unrecorded meeting merged into this recording and removed, or null when none was merged. Stop using an absorbed ID; meeting_id is the surviving record."
    }
  },
  "required": [
    "ok",
    "meeting_id",
    "calendar_event_id",
    "absorbed_meeting_id"
  ],
  "additionalProperties": false,
  "examples": [
    {
      "ok": true,
      "meeting_id": "e_meeting_kickoff",
      "calendar_event_id": "e_calendar_kickoff",
      "absorbed_meeting_id": null
    }
  ]
}
```

