# Build with Brigg Connect your business systems and agents through one published API. API keys are currently available to selected workspaces. [Contact Brigg](mailto:axel@brigg.no) to enable access. ## Choose your integration - [Build a server integration](https://developer.brigg.app/developers/quickstart) — create a scoped workspace key and make your first call. - [Connect an agent](https://developer.brigg.app/developers/mcp) — choose personal or shared workspace access. - [Receive change events](https://developer.brigg.app/developers/webhooks) — verify signatures and handle durable delivery. ## Explore the API Browse the [API reference](https://developer.brigg.app/developers/reference) by product area and resource. Every published operation includes request fields, result schemas and access requirements. Workspace-specific app schemas are available through authenticated discovery. ## Integration essentials Understand [authentication](https://developer.brigg.app/developers/authentication), [permissions](https://developer.brigg.app/developers/permissions), [HTTP conventions](https://developer.brigg.app/developers/http) and [safe retries and limits](https://developer.brigg.app/developers/reliability). Before extending the API, read [publishing app operations](https://developer.brigg.app/developers/publishing). ## Contract lifecycle [Stable contracts](https://developer.brigg.app/developers/versioning) receive at least 30 days of notice before planned retirement. [The API changelog](https://developer.brigg.app/developers/changelog) lists changes and migration notices. For agents and client generation, use the [Markdown index](https://developer.brigg.app/developers/llms.txt), [full Markdown reference](https://developer.brigg.app/developers/llms-full.txt), and [OpenAPI specification](https://developer.brigg.app/developers/openapi.json). --- # Build your first integration Create a workspace key, discover the released API, and make your first call. API keys are currently available to selected workspaces. [Contact Brigg](mailto:axel@brigg.no) to enable access. ## Create a workspace key Open [API keys in Brigg](https://brigg.app/settings/developer) and choose your workspace's API keys. An owner or administrator creates a named key, such as **Reporting**, and selects its permissions. Start with read-only access to the apps your integration needs. Copy the secret once and store it in your server's secret manager. Workspace keys act for the integration and remain active when their creator leaves. They access permitted shared workspace data. For an agent connection, [MCP](https://developer.brigg.app/developers/mcp) supports both personal and workspace access. ## Discover available operations The authenticated catalog includes your workspace's released app operations and the platform operations allowed by the key. Draft app definitions are not part of the public API. ```sh export BRIGG_API_KEY='your_workspace_secret_key' curl 'https://api.brigg.app/v1/operations' \ -H "Authorization: Bearer $BRIGG_API_KEY" ``` The [List companies reference](https://developer.brigg.app/developers/reference/customers/ListCompanies) explains filters, sorting and the returned Company record. You can also inspect the same schema programmatically: ```sh curl 'https://api.brigg.app/v1/operations/customers.ListCompanies' \ -H "Authorization: Bearer $BRIGG_API_KEY" ``` `customers.ListCompanies` requires read access to shared CRM companies. Choose an operation from your own catalog if your key has a different grant. ## Make a call Send the operation's input object directly as the JSON request body. The response is the operation's output object directly. There are no top-level `input` or `output` wrappers. ```sh curl 'https://api.brigg.app/v1/operations/customers.ListCompanies' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data '{"limit":10}' ``` For a workspace with one matching company, the response looks like this (fictional data): ```json { "items": [ { "id": "e_company_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "name": "Example Consulting", "industry": "konsulent", "website": "https://example.com" } } ] } ``` Your workspace may return `{"items":[]}`. When `next_cursor` is present, pass it as `cursor` to continue with the same filters and sort. The `konsulent` industry value means consulting; API enum values stay stable across UI languages. Queries like this one can be retried safely. Before your first create or update call, choose a stable `Idempotency-Key` and reuse it if the request needs a retry. See [retries and limits](https://developer.brigg.app/developers/reliability). ## Generate a client or help an agent Download your key's [workspace OpenAPI specification](https://api.brigg.app/v1/openapi.json) using the same authorization header. Its schemas describe the released operations visible to that credential. The [public platform specification](https://developer.brigg.app/developers/openapi.json) contains platform contracts only. Agents can read the [Markdown documentation index](https://developer.brigg.app/developers/llms.txt), discover operations, inspect schemas, and invoke the same contracts through MCP. Never paste an API key into a chat transcript. --- # Authentication Choose workspace API keys or personal and workspace MCP connections. API keys are currently available to selected workspaces. [Contact Brigg](mailto:axel@brigg.no) to enable access. ## Workspace API keys Send your secret key in the `Authorization: Bearer …` header on every HTTP request. Keys are named workspace credentials with explicit grants. Their creator is recorded for audit; the integration's access does not depend on the creator remaining a member. Owners and administrators create, revoke, and replace workspace keys in [API keys in Brigg Settings](https://brigg.app/settings/developer). Revocation prevents subsequent requests. When replacing a key, deploy the replacement credential to your integration before revoking the old one. Store keys on a server or in a trusted agent client's secret store. Secret workspace keys must not be embedded in websites, mobile bundles, URLs, logs, or documentation. ## Member delegation An administrator can allow a workspace key or shared MCP connection to act for **selected members** or **all current and future members**. The default is **Workspace only**. Existing credentials keep that default. For an HTTP call, select the member with `Brigg-Act-As`: ```sh curl 'https://api.brigg.app/v1/operations/documents.ListDocuments' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H "Brigg-Act-As: $BRIGG_ACT_AS" \ -H 'Content-Type: application/json' \ --data '{"scope":"user"}' ``` List the active members your credential may use: ```sh curl 'https://api.brigg.app/v1/delegation/members' \ -H "Authorization: Bearer $BRIGG_API_KEY" ``` The response is `{ "items": [{ "id": "account_example", "name": "Alex Taylor" }] }`. Use the returned `id`, not an email address. Only members authorized by the stored delegation grant are returned. With the [server helper](https://developer.brigg.app/developers/files), create a client for each identity: ```typescript const brigg = createBriggClient({ apiKey: process.env.BRIGG_API_KEY!, actAs: process.env.BRIGG_ACT_AS!, }); ``` The request must satisfy **both** the key's approved operations and resources **and** the member's current permissions. This includes their private data. Disabled members and members outside the credential's workspace cannot be selected. Omitting the header uses workspace access, even on a key with delegation enabled. Use the same member and idempotency key when retrying. Receipts and open uploads are isolated by credential and member. Audits record the credential and effective member. Changing a member's permissions or revoking the credential affects subsequent requests and background callbacks. Rate limits remain shared by credential and workspace; changing members does not reset them. ## Agents using MCP MCP clients use OAuth rather than API keys. Choose personal access for an agent acting with your own permissions, or workspace access for a shared integration. See [connect an agent with MCP](https://developer.brigg.app/developers/mcp) for setup, identity and revocation. ## Existing integrations Existing MCP connections retain their personal identity, granted scopes, and launched tool contracts. Reconnecting is not required merely because the public operation catalog has expanded. Existing conversion-tracking keys retain their conversion permissions. A previously issued key does not automatically gain the expanded operation API. Browser-safe publishable conversion keys remain limited to conversion tracking. --- # Choose permissions Use read-only, app selection, or custom grants with one underlying permission model. ## Start with a helper The permission selector provides shortcuts for common integrations: | Helper | Use it for | | --- | --- | | Read only | Reporting, search, and synchronization that only retrieves data | | Read and edit | Integrations that create or modify selected shared records | | App selection | Group relevant resources and operations by the app they belong to | | Custom | Select individual resources and operations | Helpers produce concrete permissions for review. Adding a new operation later does not silently broaden an existing credential. App selection includes the relevant shared platform resources used by that app. ## Identity and grant work together A personal MCP connection has the intersection of the member's live access and the connection's grant. A workspace key or workspace MCP connection starts with its approved shared-data grant. An administrator may also approve [member delegation](https://developer.brigg.app/developers/authentication#member-delegation). Each delegated call intersects that grant with the selected member's current access, including private records. Read-only access excludes commands. Resource restrictions also apply to generic record operations, nested operations, and background work started by a call. An operation's availability does not override the workspace boundary or private-record access rules. Some shared resources retain steward restrictions. Workspace connections cannot update or delete another steward's records merely because a grant includes the type. The workspace helper excludes these edits where needed, including shared meeting templates; personal connections and delegated requests retain the selected member’s existing stewardship permissions. ## Sensitive actions The authenticated catalogue contains callable operations only. It does not include human-only actions, and there is no approval flag to check on every call. | Workflow | API support | Human step | | --- | --- | --- | | Read and update approved records | Call the published operation with the required grants | Approve the credential once in Settings | | Configure a webhook | Prepare the subscription and its resource selection | An administrator reviews and enables it in Brigg | | Support replies and newsletters | Prepare or edit the content | A person approves sending in Brigg | | Automations | Read, pause or delete existing rules | Create or resume them in Brigg | | File signing | Upload the file, request signatures and read progress | Each recipient signs; the API cannot sign for them | | Workspace API keys and provider connections | Read the published management views | Create keys and complete provider consent in Brigg | Sending, spending, access changes and sensitive exports require individual operation selection where the permission selector marks them as sensitive. Preparation never grants permission to perform the later human step. Each workflow guide identifies that step explicitly. ## Diagnose refused calls A `403` response means the credential lacks access to the operation or its resources. Use the credential's authenticated catalog to see what it can call. Review the grant in Settings when the integration needs additional access; do not automatically retry a permission refusal. --- # Upload and use files Upload bytes once, then use a stable file ID for downloads and attachments. Use the file operations to bring a PDF, image or other document into Brigg. You receive a stable `file_id`; storage paths and provider credentials stay inside Brigg. Give the API key access to `documents.CreateUpload`, `documents.GetUploadPart`, `documents.CompleteUpload` and the operations that will use the file. Choose an [idempotency key](https://developer.brigg.app/developers/reliability) for each command and reuse it when retrying that command. ## Upload from your server Download the [Node.js server helper](https://developer.brigg.app/developers/client.mjs) into your integration as `brigg.mjs`. For TypeScript, also save the [type declarations](https://developer.brigg.app/developers/client.d.mts) beside it as `brigg.d.mts`. It has no third-party dependencies. Use Node.js 22 or later and keep the API key on your server. ```typescript import { createBriggClient } from "./brigg.mjs"; const brigg = createBriggClient({ apiKey: process.env.BRIGG_API_KEY!, baseUrl: "https://api.brigg.app", }); const file = await brigg.uploadFile("./Report.pdf", { contentType: "application/pdf", visibility: "workspace", requestId: "report-2026-11-upload", }); console.log(file.file_id); ``` This streams the local file, handles transfers of any supported size, waits for scanning and returns the verified file metadata. You do not split files, store part receipts or handle temporary URLs. A `Blob` is also accepted; supply its `filename` in the options. Keep `requestId` with your integration's job and reuse it with the **same unchanged file and options** after an interruption. The helper checks for an already completed transfer before sending bytes. A different file or an expired upload needs a new request ID. The returned `file_id` remains the same for that upload. Pass an `AbortSignal` as `signal` to cancel a transfer or scan wait. Cancellation stops the client; use `documents.CancelUpload` if you also want to cancel the upload. Blocked scans, quota failures and other errors are returned to your code. `BriggApiError` includes `code`, `status`, `details`, the server's `requestId` and `retryAfter` when available. The helper uses the operations below and the same permissions and limits. Bytes go directly to the transfer service, so a large document does not need to fit inside a JSON API request. ## Upload with HTTP The following steps are useful when using another language or implementing resumable and parallel transfers yourself. ### Start an upload Send the original filename, media type and exact byte length. A workspace-only call must choose `workspace` visibility. With member delegation, use `personal` to keep the resulting document in that member’s private files. Personal MCP connections may also choose `personal`. ```sh curl 'https://api.brigg.app/v1/operations/documents.CreateUpload' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H 'Idempotency-Key: agreement-upload-2026-11-10' \ --data '{"filename":"Agreement.pdf","content_type":"application/pdf","size_bytes":48231,"visibility":"workspace"}' ``` This example's fictional PDF is 48,231 bytes. Use the size of your actual file. The response describes how to transfer it: ```json { "upload_id": "upl_example", "state": "uploading", "expires_at": 1794387600000, "mode": "single", "part_size": 48231, "part_count": 1 } ``` An upload lasts 24 hours. Only the credential that created it may read its status, issue transfer URLs, complete it or cancel it. After completion, normal file and record permissions govern the file. ### Transfer the bytes Request a transfer URL for part 1: ```sh curl 'https://api.brigg.app/v1/operations/documents.GetUploadPart' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data '{"upload_id":"upl_example","part_number":1}' ``` The response includes `url`, `method: "PUT"`, `content_type`, `size_bytes` and `expires_at`. Send the exact bytes to that URL with the returned media type. Do not send your Brigg API key to the transfer URL. ```sh curl "$UPLOAD_URL" \ -X PUT \ -H 'Content-Type: application/pdf' \ --data-binary '@Agreement.pdf' ``` A transfer URL is a temporary credential. Keep it out of logs and public pages. If it expires before the transfer finishes, request another URL for the same part and retry. For `mode: "multipart"`, split the file into `part_size` byte chunks. The final chunk contains the remainder. Request and upload parts `1` through `part_count`. Brigg collects their transfer receipts when you complete the upload. Parts may be transferred in parallel and an interrupted part can be retried independently. ### Complete and scan After all bytes have transferred, complete the upload with its ID. The same request works for single and multipart uploads: ```sh curl 'https://api.brigg.app/v1/operations/documents.CompleteUpload' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H 'Idempotency-Key: agreement-complete-2026-11-10' \ --data '{"upload_id":"upl_example"}' ``` Existing clients may still send the optional `parts` array with part numbers and ETags. New integrations can omit it. An `upload_incomplete` error means one or more parts have not arrived with their expected byte lengths. Brigg checks the byte length, file type and malware scan before creating the file. A refusal whose `details.error` is `file_scan_pending` means scanning is still running: wait the `retry_after` seconds in the error details, then retry completion with the same input and idempotency key. A blocked file cannot be completed. Successful completion returns: ```json { "file_id": "f_example", "filename": "Agreement.pdf", "content_type": "application/pdf", "size_bytes": 48231, "visibility": "workspace", "scan_status": "clean" } ``` Repeating completion returns the same file. Store `file_id` in your integration. You can read the upload's state through `documents.GetUpload` or cancel an unfinished upload through `documents.CancelUpload`. ## Attach or download the file [Attach document](https://developer.brigg.app/developers/reference/documents/AttachDocument) accepts the completed `file_id` and the target record's `entry_id`. The key needs the attachment operation and access to the target resource type. Attaching a document follows Brigg's existing visibility rules; it does not grant arbitrary access to a private file. Use [Get file](https://developer.brigg.app/developers/reference/documents/GetFile) for current metadata and [Get file download](https://developer.brigg.app/developers/reference/documents/GetFileDownload) for a temporary download URL. Each request checks current access. The download points to the verified version of the file, so an old upload URL cannot replace the bytes behind that download. The server helper can obtain and use a fresh download URL in one call: ```typescript import { createWriteStream } from "node:fs"; import { Readable } from "node:stream"; import { pipeline } from "node:stream/promises"; const response = await brigg.downloadFile(file.file_id); await pipeline(Readable.fromWeb(response.body), createWriteStream("./Downloaded.pdf", { flags: "wx" })); ``` This streams the download without buffering the whole file in memory. It checks current access each time and never sends the Brigg API key to the file-transfer service. Next, [send a PDF for signature](https://developer.brigg.app/developers/signing) or [import contacts](https://developer.brigg.app/developers/imports). See the [files and uploads reference](https://developer.brigg.app/developers/reference/areas/documents/files-and-uploads) for all file operations. ## One document identity Every document has a stable `file_id`, whether it is an uploaded file, collaborative text or a generated document. Find it through [List documents](https://developer.brigg.app/developers/reference/documents/ListDocuments) or [Search documents](https://developer.brigg.app/developers/reference/documents/SearchDocuments). [Get document](https://developer.brigg.app/developers/reference/documents/GetDocument) returns its kind and supported reads and exports for the acting member. | Document kind | Bring it into Brigg | Get its content out | |---|---|---| | `file` | Upload original bytes using the flow above. | Download the original bytes with GetFileDownload, or ExportDocument with `format: "original"`. | | `text_document` | CreateTextDocument accepts Markdown. ConvertDocumentToTextDocument can copy a plain-text upload or a generated document's prose into a new text document. | ReadTextDocument returns current Markdown. ExportDocument renders Markdown, PDF or Word. | | `generated_document` | Created in Brigg from a template or a document workflow. | ExportDocument renders PDF or Word from the selected saved state. | Uploading a PDF or Word file preserves that file; it does not make the content collaboratively editable. Conversion to a text document supports plain text and generated prose, **not PDF or Word import**. Conversion creates a separate document and leaves the original unchanged; styling and layout are not copied into Markdown. GetDocument and ExportDocument require [member delegation](https://developer.brigg.app/developers/authentication#member-delegation). Use the same approved member when inspecting, exporting and downloading private content. Workspace credentials can still upload and download shared original files without delegation. ### Export and download Inspect `capabilities.export.formats` before choosing a format. The public API uses the same `file_id` throughout; internal bundle and storage identifiers are unnecessary. ```typescript const brigg = createBriggClient({ apiKey: process.env.BRIGG_API_KEY!, baseUrl: "https://api.brigg.app", actAs: process.env.BRIGG_ACT_AS!, }); const exported = await brigg.call("documents.ExportDocument", { file_id: "f_project_notes", format: "pdf", }, { requestId: "project-notes-export-2026-11-10" }); const response = await brigg.downloadFile(exported.file_id); await pipeline(Readable.fromWeb(response.body), createWriteStream("./Project-notes.pdf", { flags: "wx" })); ``` Use the stream imports shown in the download example above. `exported.source.file_id` identifies the unchanged source; `exported.file_id` identifies the downloadable result. A rendered export is a new private file owned by the acting member and is not automatically filed into Documents. Exporting `original` returns the original file ID and makes no copy. The default revision is `saved`. For generated documents this excludes private drafts; if no saved state exists, you receive `no_saved_version`. Set `revision: "current"` explicitly to include the acting member's own draft. For collaborative text, both selections capture live content and fail if that content cannot be flushed. To export an exact historical state, pass an accessible `version_id` as `revision`; Brigg never silently substitutes another version. The result's `source.revision` is an opaque content token; `source.version_id`, when present, is a historical version you can select later. They serve different purposes. Retrying with the same idempotency key returns the same export; a new snapshot needs a new key. ### Edit text without losing changes [Read text document](https://developer.brigg.app/developers/reference/documents/ReadTextDocument) returns current Markdown and a `revision`. Send that token as `expected_revision` with [Edit text document](https://developer.brigg.app/developers/reference/documents/EditTextDocument) or [Replace text document](https://developer.brigg.app/developers/reference/documents/ReplaceTextDocument). The comparison and edit happen atomically against live content. If someone edits first, you receive `409 revision_conflict` and your change is not applied. Re-read, reconcile your edit, then submit a new command with a new idempotency key. Omitting `expected_revision` deliberately edits the latest content; a full replacement can then overwrite intervening changes. A revision token is not a history version ID. ## Private files To upload into a member's private files, use a credential with [member delegation](https://developer.brigg.app/developers/authentication#member-delegation), set the helper's `actAs` to their account ID, and choose `visibility: "personal"`. Keep that identity for all calls in the upload. A different member or credential cannot take over an open upload. Workspace uploads continue to use `visibility: "workspace"`. --- # Send a PDF for signature Upload a PDF, invite recipients, track their signatures and download the completed document. Start with the PDF you already have. Brigg keeps a fixed copy for this signing request, sends each recipient a private invitation, and records their consent. Your integration never signs on a person's behalf. ## Before you start Create a workspace API key with `documents.CreateUpload`, `documents.GetUpload`, `documents.GetUploadPart`, `documents.CompleteUpload`, `signing.RequestFileSignatures`, `signing.GetSigningRequest` and `signing.GetSigningDocument`. Add event-history, cancellation, deadline or reminder permissions only if your integration needs them. Follow [Upload and use files](https://developer.brigg.app/developers/files) to upload your PDF and complete its scan. Save the returned `file_id`. The PDF must be readable without a password. ## Invite the recipients Use the same `Idempotency-Key` when retrying the same request. A fresh key starts a separate signing request and sends another invitation. ```bash curl 'https://api.brigg.app/v1/operations/signing.RequestFileSignatures' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H 'Idempotency-Key: agreement-2026-001' \ --data '{ "file_id": "f_agreement", "title": "Consulting agreement", "signers": [{"email": "alex@example.com", "name": "Alex Morgan"}], "signature_method": "standard", "message": "Please review and sign our agreement." }' ``` ```json { "signing_request_id": "sig_agreement", "status": "pending", "invitation_failures": [] } ``` `standard` collects a typed-name e-signature with its time and evidence. `bankid` uses Norwegian BankID when configured and charges the workspace's credit. The recipient completes either method themselves. If `invitation_failures` contains addresses, the request still exists. Use `signing.RemindSigners` for the affected pending recipients instead of creating a second request. ## Check progress Call [Get signing request](https://developer.brigg.app/developers/reference/signing/GetSigningRequest) with the returned `signing_request_id`. The response contains each recipient's status and the request's `pending`, `completed`, `cancelled` or `expired` state. `completed` means everyone has signed. The signed archive may still be generating; wait until `file_id` is non-null before downloading it. Poll with a delay and follow [rate limits and safe retries](https://developer.brigg.app/developers/reliability). A workspace key reads the requests it created. A personal connection uses that person's signing access. A private source stays visible only to its owner and the invited recipients. ## Download the signed PDF ```bash curl 'https://api.brigg.app/v1/operations/signing.GetSigningDocument' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data '{"signing_request_id":"sig_agreement","version":"signed"}' ``` The response contains `url`, `filename` and `expires_at`. Download the file before the link expires, or request a fresh link. Use `version: "original"` to download the fixed source shown to recipients. For typed-name signatures, the archive contains the original PDF pages followed by the signature evidence. BankID returns a cryptographically signed PDF, which Brigg preserves without rewriting. ## Manage a pending request - [Remind signers](https://developer.brigg.app/developers/reference/signing/RemindSigners): resend invitations to pending recipients. - [Change the deadline](https://developer.brigg.app/developers/reference/signing/SetSigningDeadline): keep the same document and signatures while extending or shortening the deadline. - [Cancel signing](https://developer.brigg.app/developers/reference/signing/CancelSigning): stop further signatures. Completed requests cannot be cancelled. The sender controls these actions. A request's document cannot be replaced after invitations go out. To sign a different PDF, cancel the pending request and create a new one. ## Read the event history Use `signing.ListSigningEvents` to read the request’s history. Events are ordered oldest first and have stable `event_id` values for deduplication. Follow `next_cursor` while `has_more` is true. A new poll starts from the first page; retain processed event IDs. This is a history read, not a webhook subscription. Every page checks your current access to the request. Events cover requests, opening, signing, reminders, deadline changes, cancellation and archive completion. They omit recipient IP addresses, access links, document contents and internal audit details. --- # Import contacts from a file Upload a CSV, TSV or vCard, review the rows, then create contacts with ordinary record operations. Use this flow when your integration already has a contact file. Preparation never creates or changes a contact. You decide which validated rows to apply and whether they match existing people. ## Upload the source Follow [Upload and use files](https://developer.brigg.app/developers/files). Use a UTF-8 CSV, TSV, plain-text table or vCard and save the completed `file_id`. The contact parser supports up to 4,000,000 text characters per file. A larger source is refused; no rows are silently truncated. Give the key access to `customers.PreviewContactImport`, `customers.CreatePerson`, and read/write access to `core:Person`. Add `customers.ListPeople` and `customers.UpdatePerson` if you need to match and update existing contacts. A contact is a customer record; creating one does not invite a workspace member or assign an account role. ## Map and review For a table, map column numbers starting at zero. For example, this source has a header and three columns: ```csv Name,Email,Job title Alex Morgan,alex@example.com,Operations manager Taylor Chen,taylor@example.com,Project lead ``` ```bash curl 'https://api.brigg.app/v1/operations/customers.PreviewContactImport' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data '{"file_id":"f_contacts","has_header":true,"mapping":{"display_name":0,"email":1,"title":2},"limit":50}' ``` A vCard describes its own fields, so omit `mapping` for that format. The supported fields are `display_name`, `email`, `phone`, `title` and `linkedin_url`. ```json { "file_id": "f_contacts", "row_count": 2, "duplicate_count": 0, "invalid_count": 0, "items": [ {"row":1,"status":"ready","data":{"display_name":"Alex Morgan","email":"alex@example.com","title":"Operations manager"}}, {"row":2,"status":"ready","data":{"display_name":"Taylor Chen","email":"taylor@example.com","title":"Project lead"}} ], "has_more": false, "next_cursor": null } ``` `ready` rows contain `data` that satisfies the published Create person contract. An `invalid` row contains an explanation. `duplicate` means an earlier row in this source has the same normalized email, or the same name when there is no email. It does not mean the person already exists in Brigg. Empty source lines are ignored by the parser; `row` counts parsed contact rows after the header. When `has_more` is true, pass `next_cursor` as `cursor` with the same file and mapping. Each page checks current file access. A cursor cannot be reused with a different source, mapping or credential. ## Apply the reviewed rows For a new person, send the row's `data` to [Create person](https://developer.brigg.app/developers/reference/customers/CreatePerson): ```bash curl 'https://api.brigg.app/v1/operations/customers.CreatePerson' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H 'Idempotency-Key: contacts-november-row-1' \ --data '{"data":{"display_name":"Alex Morgan","email":"alex@example.com","title":"Operations manager"}}' ``` Store the returned `item.id`. Reuse this row's idempotency key when retrying its creation, so a timeout cannot create a duplicate. If you are reconciling existing contacts, use [List people](https://developer.brigg.app/developers/reference/customers/ListPeople) to find candidates and choose the target explicitly before [Update person](https://developer.brigg.app/developers/reference/customers/UpdatePerson). Preparation does not guess merges or grant permission to write. Skip invalid or duplicate rows until your integration has resolved them. A failed write does not undo other rows: retain each row's result so you can resume safely. --- # Publish an app API Explicitly select public operations and fields before releasing an app contract. ## Choose the public surface An app's internal operations can change with its implementation. Publishing an operation creates a customer contract with a separate release decision. Mark a resource or authored operation with `external: { "stability": "stable" }` in the app manifest's `api` block. Select each public field with `api: true` in its `FieldSpec`. This applies to resource fields and to an authored operation's request and response fields. Declared nested object fields also need their own `api: true`. New internal fields remain private until explicitly selected and released. For example, this manifest declaration publishes an authored query: ```json { "api": { "operations": { "ReadMetrics": { "kind": "query", "description": "Read the number of open tickets.", "external": { "stability": "stable" }, "input": { "queue": { "type": "string", "api": true } }, "output": { "count": { "type": "number", "api": true } } } } } } ``` Implement the matching `ReadMetrics` handler in the app's `api.ts`. With the assigned namespace `helpdesk`, this operation is published as `apps.helpdesk.ReadMetrics`. Use that name over HTTP or MCP. The handler and internal app calls continue to use `helpdesk.ReadMetrics`. Publishing the manifest does not create the handler or grant credentials access to it. ## Validate and release Validate the app and review the external schema before saving the release. A required input field cannot be kept private: callers need every required input to invoke the operation. Validation refuses such a contract rather than exposing that field automatically. Saving a release makes its approved public contract available to authenticated discovery and workspace OpenAPI generation. Draft changes remain internal. Existing keys and MCP grants still need approval for any newly added operations or resource access. Copied and installed apps start with their own publication boundary. Their inherited manifest declarations do not expose an API automatically. Validate and save a release to approve that app's public contract, then choose the operations in the credential's permissions. Discovery uses the frozen contract registered for the current saved version, so later changes to internal schema generators cannot rewrite it. ## Evolve the contract Add optional inputs and compatible outputs while retaining supported behavior. Removing a promised field or operation, narrowing accepted inputs, or widening a response enum can break existing integrations. Publication checks compare against supported released contracts, including contracts added by later app releases. Rolling an app back cannot erase a contract customers already use. Keep the supported operation available while replacing the underlying feature, or follow the [retirement policy](https://developer.brigg.app/developers/versioning) with a migration path and at least 30 days of notice for stable contracts. --- # Requests, lists, and errors Flat operation bodies, cursor pagination, stable errors, and request identifiers. ## Field names and values Built-in operations use `snake_case` for request and response fields. Record filters and sort also use those published names, for example `data.start_time`; internal field spellings are not accepted. App-defined fields keep the names explicitly published by that app. Dictionary keys and user content are not renamed. Timestamp fields declare their units in the operation reference. Record timestamps use Unix milliseconds; ISO date-time strings remain strings where specified. Monetary fields on deals, products and product lines are Norwegian øre (100 øre = NOK 1). These records do not support selecting another currency. ## Operation requests The API base is `https://api.brigg.app/v1`. Discover operations with `GET /operations`, inspect one with `GET /operations/{name}`, and invoke it with `POST /operations/{name}`. Operation names are case-sensitive. Follow the released schema for each operation. Send `Content-Type: application/json` and a JSON object matching the input schema. Responses match the output schema directly. Schema definitions use the terms input and output; those terms do not add wrappers to the wire format. ## Operation names Names follow product areas, such as `customers.ListCompanies` and `meetings.ListMeetings`. Use the exact published name in operation requests. Operations published by workspace apps use `apps..`, for example `apps.helpdesk.ReadMetrics`. Discover the exact names available to your credential with `GET https://api.brigg.app/v1/operations`. ## Lists and pagination List contracts use `items` and an optional `next_cursor`: ```json { "items": [{ "id": "example_record" }], "next_cursor": "opaque_cursor" } ``` Use the next cursor as the following request's `cursor`, keeping the same filters. Record-list operations default to 100 rows per page and accept a positive integer `limit`; they do not impose a fixed maximum. Other list operations document their own defaults, bounds and cursor support. Cursors are opaque: store and pass them unchanged. The final page omits `next_cursor`. An empty result is `{ "items": [] }`. Do not infer that the list is complete from the number of items in a page. ## Errors HTTP failures use a stable error code, a human-readable message, and optional structured details: ```json { "error": "rate_limited", "message": "The request limit has been reached." } ``` Agents and integrations should branch on `error` and structured `details`, rather than parsing the message. | Status | Meaning | What to do | | --- | --- | --- | | 400 | Invalid input | Correct the request using the schema and details | | 401 | Missing, invalid, or revoked credential | Check authentication | | 403 | Insufficient access or approval required | Review permissions or complete approval | | 404 | Operation or permitted resource not found | Check the catalog and identifier | | 409 | Conflict or incompatible retry | Reconcile the operation's state | | 429 | Rate or resource limit reached | Respect `Retry-After` and back off | | 5xx | Server failure | Follow the operation's retry rules | ## Request identifiers The `X-Request-Id` response header identifies the request for diagnostics. Include it when reporting a failed call. Request IDs identify attempts; an idempotency key identifies the logical command across retries. See [safe retries and limits](https://developer.brigg.app/developers/reliability) before retrying a command. ## Iterate through a list on your server The [Node.js server helper](https://developer.brigg.app/developers/client.mjs) exposes each row as an async iterator. It follows the server's cursors, preserves your filters and sort order, and keeps only the current page in memory: ```typescript import { createBriggClient } from "./brigg.mjs"; const brigg = createBriggClient({ apiKey: process.env.BRIGG_API_KEY!, baseUrl: "https://api.brigg.app" }); for await (const company of brigg.items("customers.ListCompanies", { filters: [{ field: "data.name", op: "contains", value: "Example" }], sort: { field: "data.name", direction: "asc" }, })) { console.log(company.id, company.data.name); } ``` Use this with operations that return `items` and an optional `next_cursor`. Plain `call(operation, input, options)` returns the original response, which is useful when your application stores its own cursor. Commands require an explicit `requestId` in `options`; reuse it when retrying the same command. The helper does not automatically repeat an ambiguous command failure. ## Synchronize records without duplicates Use a resource's Upsert operation with `external_ref: {namespace, id}` for a permanent source-system match. Choose the namespace once and use the source system's record ID. The reference is scoped to the workspace, resource type and private/workspace ownership; it survives API key replacement and the retry-receipt window. It never guesses a match by email or name. For larger files, [start a resumable record import](/developers/reference/integrations/StartRecordImport). Upload UTF-8 NDJSON with one complete Upsert request per line, then inspect progress and per-row outcomes. It applies the same grants, validation and webhooks as individual calls. Invalid rows are reported; interrupted work can resume without duplicating completed rows. --- # Safe retries and limits Use idempotency keys, honor retry instructions, and bound integration work. ## Retry commands safely Commands require an `Idempotency-Key` header containing 1–200 characters. Generate one unique value for each logical action and reuse that value with the same operation and input when retrying that action. ```sh curl 'https://api.brigg.app/v1/operations/apps.your_app.YourCommand' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H 'Idempotency-Key: integration-action-unique-id' \ --data '{"replace_with":"the_declared_input"}' ``` This command is a template: choose a released operation and supply the exact input from its schema. A timeout is not proof that the action failed. Reconcile or retry with the same idempotency key; do not generate a new key merely because the response was lost. Command receipts are retained for 30 days. Do not rely on an old key to prevent duplicate work after that window. Keep your own durable integration identifiers for actions that may be replayed much later. Retry identities belong to the credential that started the action. Reconcile pending actions with the original credential before rotating a key or reconnecting MCP. Reusing the same retry value under a new credential does not replay the original action. ## Rate limits Each credential has a budget of 600 requests per minute. Each workspace has a combined budget of 1,200 requests per minute across HTTP and MCP. Creating additional keys or switching transports does not multiply the workspace budget. All authenticated MCP requests retain an additional limit of 120 requests per connection per minute, including discovery and operation calls. When Brigg returns `429`, inspect the error details and wait at least the `Retry-After` interval before retrying. Use exponential backoff with jitter for repeated transient failures. Avoid synchronized polling across credentials. ## Resource and cost controls Some operations have additional page-size, upload, bulk-input, concurrency, or spending limits. Their schemas and error details describe the applicable constraint. Permission to invoke an operation does not promise unlimited background work or unlimited credits. Process paginated lists one page at a time and keep only the concurrency needed for your workflow. Some lists return all allowed items in one response and omit `next_cursor`. For longer work, use the operation's returned job identifier and its documented status operation. Resource webhooks can notify you when published shared records change. ## Diagnose an integration Keep the operation name, `X-Request-Id`, HTTP status, stable error code, and timing in your logs. Keep credentials and sensitive request/response bodies out of diagnostic logs. Brigg records customer adoption and operation outcomes across both HTTP and MCP for support and compatibility planning. --- # Connect an agent with MCP Connect personal or shared workspace agents and discover the full published API. ## Connect Add this remote MCP server to your client: ```text https://api.brigg.app/mcp ``` The client starts Brigg's OAuth authorization flow. Sign in, choose the workspace and identity mode, review permissions, and approve the connection. Personal access follows your live permissions. Workspace access uses an administrator-approved grant, with optional member delegation. Manage and revoke connections in [Brigg Settings](https://brigg.app/account/mcp). Tokens belong in the client credential store, never in an agent prompt. ## Let the client discover its tools After connecting, the MCP server supplies the tools, descriptions and argument schemas the client needs. Your agent can discover and inspect available operations before using them. The catalog follows the connection's approved permissions. The HTTP reference documents operations available to workspace API keys. Operations that require a member’s identity are marked as requiring delegation in the HTTP reference. MCP discovers the same operation contracts through the protocol. ## Personal or workspace access Use personal access to work with your own permitted meeting content and personal records. Use workspace access for shared reporting, CRM synchronization, and an agent that serves an ongoing business process independently of one employee. Workspace access does not imply access to a colleague's private records. Sensitive operations may require a person to approve a proposed action. ## Existing MCP clients The launched MCP tools, their schemas, and existing personal OAuth grants remain supported. Existing clients do not need to rename tools or reconnect to retain their current access. To use the new operation tools, explicitly request the `brigg.operations` OAuth scope and approve the concrete operation permissions. Existing grants do not automatically gain this access. Use the [HTTP quickstart](https://developer.brigg.app/developers/quickstart) when you are building a server integration with an API key. ## Delegating member access An administrator may approve selected members or all current and future members for a shared connection. Use `list_delegation_members` to obtain authorized member IDs. Pass `act_as` alongside `name`, `arguments` and `request_id` on `invoke_operation`, or alongside the filters on `list_operations` and `read_operation`. It belongs outside the operation arguments. The selected member's live permissions and the connection's approved grant both apply, including access to private records. Without `act_as`, shared connections continue to use workspace access. Personal connections cannot select another member. The existing personal tools keep their current contracts. --- # Receive webhooks Subscribe to committed changes, verify signatures, and recover failed deliveries. ## Subscribe In [Brigg webhook settings](https://brigg.app/settings/webhooks), add a public HTTPS endpoint and select the events and resource types your integration needs. An authorized administrator approves the export. An agent can discover event schemas and prepare the configuration for review. Webhook subscriptions carry explicit access permissions. Adding a resource type or event later does not silently expand an existing subscription. Resource notifications export shared workspace records. Personal private streams are outside v1. Read the [event reference](https://developer.brigg.app/developers/events) for exact event schemas. The existing `meeting.completed` contract and signature remain supported for existing subscriptions. ## Choose resource types A resource type identifies a kind of record. For example, `core:Company` means customer companies; it is different from the public operation namespace `customers`. Workspace apps have their own qualified type identifiers. Copy these values from discovery rather than constructing them. 1. Call `GET https://api.brigg.app/v1/operations` using a key permitted to read the records you need. 2. Collect the distinct `resource` values on those record operations. An operation such as `customers.ListCompanies` declares `resource: "core:Company"`. 3. Pass the exact selected values as `resource_types` to [Prepare webhook](https://developer.brigg.app/developers/reference/webhooks/PrepareWebhook), then open the returned `approval_url` on your Brigg application origin. An administrator reviews the destination, event and data access before the subscription is created. ```json { "url": "https://example.com/webhooks/brigg", "event": "resource.updated", "resource_types": ["core:Company"] } ``` The key needs both `webhooks.PrepareWebhook` and read access to each selected type. If a needed resource is missing from discovery, review the key's permissions with an administrator. Private records and unpublished types cannot be subscribed to. App-specific types depend on the apps released in your workspace, so there is no universal static enum. `resource.created`, `resource.updated` and `resource.deleted` require at least one resource type. For legacy `meeting.completed`, omit `resource_types`: that event uses its existing approval and payload contract. New types are never subscribed automatically. Creating a webhook remains a human approval step in Settings. `CreateWebhook` is not an HTTP operation; the API prepares a proposal and can inspect or replay an already approved stream. ## Find the approved subscription After the administrator approves a proposal, call [List webhook subscriptions](https://developer.brigg.app/developers/reference/webhooks/ListWebhookSubscriptions). Your key needs that operation and read access to every resource type on the subscription. The response includes `webhook_id`, event, selected types, enabled state and delivery timestamps. It does not reveal the destination or signing secret. Use `webhook_id` with the event, delivery and replay operations. An administrator supplies the signing secret to the receiving service through a secure channel. Subscriptions outside the key's current permissions are absent from the list; removing a permission also removes access to their delivery history. ## Coverage Resource events cover committed changes to published shared records, including API calls, imports, enrichment and background updates. Events capture the database change in the same transaction; rolled-back writes, unchanged values, drafts, private records, project records and internal member profiles do not produce resource notifications. `changed_fields` uses the same published names as the record API. The curated `meeting.completed` notification remains supported independently. Treat notifications as prompts to read the current record. Reconcile periodically to recover from receiver downtime, changes made before your subscription existed, or periods when it was disabled. ## Process notifications Verify the signature against the exact raw request bytes before parsing JSON. Deduplicate using the stable event identifier, persist or queue the event, and respond with a successful status promptly. Your endpoint must respond within 10 seconds; redirects are not followed. Notifications may arrive more than once or out of order. Use the resource identifier and version where provided, and retrieve current data through an API credential with the required access. Deletion notifications identify the deleted resource without requiring it to remain readable through the record API. ## Verify signatures Resource event deliveries use these headers: | Header | Value | | --- | --- | | `X-Webhook-Signature` | `v1=` followed by the hexadecimal HMAC-SHA256 signature | | `X-Webhook-Timestamp` | Unix time in seconds for this delivery attempt | | `X-Webhook-Event-Id` | Stable event identifier; use it for deduplication | | `X-Webhook-Delivery-Id` | Delivery identifier for diagnostics | The JSON body contains the event name. Sign the timestamp, a period, and the exact raw body bytes: `HMAC-SHA256(secret, timestamp + "." + rawBody)`. Check that the timestamp is within five minutes of your receiver's clock. Each retry has a fresh timestamp and signature; the event identity and payload remain unchanged. This Node.js example verifies a resource event before JSON parsing. Pass the raw request body as a `Buffer` and the incoming HTTP headers: ```js import { createHmac, timingSafeEqual } from "node:crypto"; export function verifyBriggWebhook(rawBody, headers, secret, now = Date.now()) { const timestamp = headers["x-webhook-timestamp"]; const signature = headers["x-webhook-signature"]; if (typeof timestamp !== "string" || !/^\d+$/.test(timestamp)) return false; if (typeof signature !== "string" || !/^v1=[0-9a-f]{64}$/.test(signature)) return false; if (Math.abs(now / 1000 - Number(timestamp)) > 300) return false; const expected = createHmac("sha256", secret) .update(timestamp + ".") .update(rawBody) .digest(); const received = Buffer.from(signature.slice(3), "hex"); return timingSafeEqual(expected, received); } ``` The existing `meeting.completed` contract uses its original hexadecimal HMAC-SHA256 signature over the raw body, without the `v1=` prefix or timestamp input. Keep that verifier for legacy subscriptions. Moving to a new signing contract requires an explicit configuration change. Treat signing secrets as server credentials. Compare signatures in constant time, reject invalid signatures, and enforce the documented timestamp tolerance for timestamped signatures. Never verify a reserialized JSON object: whitespace and field ordering affect the signed bytes. ## Recover deliveries Failed deliveries have up to eight attempts across approximately 24 hours. After the first attempt, the nominal retry times are 30 seconds, 2 minutes 30 seconds, 10 minutes 30 seconds, 30 minutes, 2 hours, 8 hours and 24 hours. Brigg respects longer `Retry-After` values on `429` and `503` responses. Retries keep the same event and delivery identifiers. Ten consecutive deliveries that exhaust this retry window disable a subscription. An active workspace owner or administrator receives a notice in their Brigg conversation. A late failure cannot override a more recent successful attempt. Repair and test the endpoint in Settings, then enable it again; this clears the failure count. While disabled, it receives no new events. Replay retained failures and reconcile records changed during the gap. Inspect delivery outcomes and attempts through the webhook operations. Replay an eligible failed event after repairing your endpoint. Replays can cause effects in your receiving system, so apply the same deduplication rules. Keep the endpoint's delivery identifiers and error details in your logs. Resource delivery history and replay availability are retained for 30 days. Delivery attempts are limited to 600 per workspace per minute and 60 per subscription per minute. Revoked access is not restored by replaying a delivery. --- # Compatibility and retirement Build against released contracts and get at least 30 days of notice for planned stable retirement. ## Released contracts The stable HTTP API lives under `/v1`. HTTP and MCP use the same published operation contracts. Draft app changes and internal fields do not automatically become part of that contract. Compatible additions can ship within v1. Clients should accept additional response fields and use stable identifiers instead of display labels. Follow each schema's treatment of enum values; do not assume that a human-readable label is a permanent identifier. Breaking replacements require a new major API contract. Existing operation behavior and webhook contracts remain available through their support period; preserving a name while changing its meaning is not a compatible replacement. ## Planned retirement Brigg gives at least **30 days' notice** before a planned retirement of a stable public operation or webhook contract. A retirement notice identifies the affected contract, the shutdown date, and the replacement or migration guidance where available. Deprecation recommends a replacement while the old contract remains available. A retirement date is the point at which the old contract stops working. Releasing a replacement does not immediately retire the original. Read the [API changelog](https://developer.brigg.app/developers/changelog) and inspect deprecation metadata in your authenticated operation schemas. Brigg captures operation use and webhook subscriptions to identify customers affected by planned changes. ## Experimental operations Experimental capabilities have an explicit stability label and require opt-in. Their stated support policy can differ from stable v1. Do not rely on an experimental operation as a stable dependency without reviewing that policy. ## Existing MCP and webhooks Existing launched MCP tools, personal grants, conversion permissions, and `meeting.completed` webhook contracts retain their supported behavior. New identity modes and operation discovery expand the API without silently widening old credentials. --- # API changelog Public API changes and migration notices, separate from the product's marketing updates. ## Public API v1 - HTTP and MCP share published operation contracts. The developer reference covers HTTP; MCP clients discover their tools through the protocol. - Workspace API keys and personal or workspace MCP connections use explicit permission grants. - HTTP operation requests and responses use flat input/output objects, with consistent list and error conventions. - Workspace and credential rate controls cover the external transports. - Expanded webhooks provide committed resource-change notifications and delivery inspection. - Existing MCP tools, personal grants, conversion keys, and legacy meeting webhooks remain supported. ## Migration notices There are no planned stable-contract retirements in this release. Future retirement notices will appear here with the affected operation or event version, replacement guidance, and a shutdown date at least 30 days after notice. --- # API reference Browse by product area, then choose a resource and operation. ## Product areas - [Automation](https://developer.brigg.app/developers/reference/areas/automation) — 1 resource, 4 operations - [Credits and usage](https://developer.brigg.app/developers/reference/areas/credits-and-usage) — 2 resources, 4 operations - [Customer service](https://developer.brigg.app/developers/reference/areas/customer-service) — 7 resources, 31 operations - [Customers](https://developer.brigg.app/developers/reference/areas/customers) — 12 resources, 57 operations - [Documents](https://developer.brigg.app/developers/reference/areas/documents) — 8 resources, 48 operations - [Domains](https://developer.brigg.app/developers/reference/areas/domains) — 4 resources, 14 operations - [Images](https://developer.brigg.app/developers/reference/areas/images) — 1 resource, 1 operation - [Integrations](https://developer.brigg.app/developers/reference/areas/integrations) — 5 resources, 12 operations - [Meetings](https://developer.brigg.app/developers/reference/areas/meetings) — 13 resources, 55 operations - [Newsletters](https://developer.brigg.app/developers/reference/areas/newsletters) — 3 resources, 12 operations - [Signing](https://developer.brigg.app/developers/reference/areas/signing) — 1 resource, 8 operations - [Tasks](https://developer.brigg.app/developers/reference/areas/tasks) — 1 resource, 6 operations - [Voice](https://developer.brigg.app/developers/reference/areas/voice) — 3 resources, 8 operations - [Web analytics](https://developer.brigg.app/developers/reference/areas/web-analytics) — 2 resources, 4 operations - [Webhooks](https://developer.brigg.app/developers/reference/areas/webhooks) — 3 resources, 8 operations - [Workspace](https://developer.brigg.app/developers/reference/areas/workspace) — 10 resources, 19 operations ## Your workspace apps Use [GET /v1/operations](https://api.brigg.app/v1/operations) with your credential to discover released workspace app operations. Their schemas are private to your workspace and are never included on this public site. Download the [platform OpenAPI specification](https://developer.brigg.app/developers/openapi.json), or fetch [your workspace specification](https://api.brigg.app/v1/openapi.json) with authentication. --- # Automation Explore automation resources and their published operations. ## Resources - [Rules](https://developer.brigg.app/developers/reference/areas/automation/rules) — 4 operations Choose a resource to explore its operations and access requirements. [Credential permissions](https://developer.brigg.app/developers/permissions) determine which operations your integration can invoke. --- # Credits and usage Explore credits and usage resources and their published operations. ## Resources - [Billing](https://developer.brigg.app/developers/reference/areas/credits-and-usage/billing) — 1 operation - [Credits and usage](https://developer.brigg.app/developers/reference/areas/credits-and-usage/credits-and-usage) — 3 operations Choose a resource to explore its operations and access requirements. [Credential permissions](https://developer.brigg.app/developers/permissions) determine which operations your integration can invoke. --- # Customer service Explore customer service resources and their published operations. ## Resources - [Contact channel](https://developer.brigg.app/developers/reference/areas/customer-service/contact-channel) — 6 operations - [Conversation](https://developer.brigg.app/developers/reference/areas/customer-service/conversation) — 6 operations - [Inbox](https://developer.brigg.app/developers/reference/areas/customer-service/inbox) — 7 operations - [Inbox message](https://developer.brigg.app/developers/reference/areas/customer-service/inbox-message) — 3 operations - [Phone numbers](https://developer.brigg.app/developers/reference/areas/customer-service/phone-numbers) — 5 operations - [Replies](https://developer.brigg.app/developers/reference/areas/customer-service/replies) — 1 operation - [Support addresses](https://developer.brigg.app/developers/reference/areas/customer-service/support-addresses) — 3 operations Choose a resource to explore its operations and access requirements. [Credential permissions](https://developer.brigg.app/developers/permissions) determine which operations your integration can invoke. --- # Customers Explore customers resources and their published operations. ## Resources - [Briefs](https://developer.brigg.app/developers/reference/areas/customers/briefs) — 4 operations - [Company](https://developer.brigg.app/developers/reference/areas/customers/company) — 7 operations - [Company discovery](https://developer.brigg.app/developers/reference/areas/customers/company-discovery) — 3 operations - [Deal](https://developer.brigg.app/developers/reference/areas/customers/deal) — 6 operations - [Email message](https://developer.brigg.app/developers/reference/areas/customers/email-message) — 2 operations - [Imports and HubSpot](https://developer.brigg.app/developers/reference/areas/customers/imports-and-hub-spot) — 4 operations - [Note](https://developer.brigg.app/developers/reference/areas/customers/note) — 6 operations - [Person](https://developer.brigg.app/developers/reference/areas/customers/person) — 6 operations - [Product](https://developer.brigg.app/developers/reference/areas/customers/product) — 6 operations - [Record enrichment](https://developer.brigg.app/developers/reference/areas/customers/record-enrichment) — 2 operations - [Sales pipeline](https://developer.brigg.app/developers/reference/areas/customers/sales-pipeline) — 6 operations - [Tags](https://developer.brigg.app/developers/reference/areas/customers/tags) — 5 operations Choose a resource to explore its operations and access requirements. [Credential permissions](https://developer.brigg.app/developers/permissions) determine which operations your integration can invoke. ## Workflow guides - [Import contacts from a file](https://developer.brigg.app/developers/imports) — Upload a CSV, TSV or vCard, review the rows, then create contacts with ordinary record operations. --- # Documents Explore documents resources and their published operations. ## Resources - [Apps and bundles](https://developer.brigg.app/developers/reference/areas/documents/apps-and-bundles) — 4 operations - [Attachments](https://developer.brigg.app/developers/reference/areas/documents/attachments) — 1 operation - [Document templates](https://developer.brigg.app/developers/reference/areas/documents/document-templates) — 9 operations - [Documents](https://developer.brigg.app/developers/reference/areas/documents/documents) — 9 operations - [Files and uploads](https://developer.brigg.app/developers/reference/areas/documents/files-and-uploads) — 7 operations - [Folders](https://developer.brigg.app/developers/reference/areas/documents/folders) — 2 operations - [Sharing](https://developer.brigg.app/developers/reference/areas/documents/sharing) — 3 operations - [Text documents](https://developer.brigg.app/developers/reference/areas/documents/text-documents) — 13 operations Choose a resource to explore its operations and access requirements. [Credential permissions](https://developer.brigg.app/developers/permissions) determine which operations your integration can invoke. --- # Domains Explore domains resources and their published operations. ## Resources - [DNS records](https://developer.brigg.app/developers/reference/areas/domains/dns-records) — 3 operations - [Domains](https://developer.brigg.app/developers/reference/areas/domains/domains) — 3 operations - [Registrant details](https://developer.brigg.app/developers/reference/areas/domains/registrant-details) — 2 operations - [Website domains](https://developer.brigg.app/developers/reference/areas/domains/website-domains) — 6 operations Choose a resource to explore its operations and access requirements. [Credential permissions](https://developer.brigg.app/developers/permissions) determine which operations your integration can invoke. --- # Images Explore images resources and their published operations. ## Resources - [Images](https://developer.brigg.app/developers/reference/areas/images/images) — 1 operation Choose a resource to explore its operations and access requirements. [Credential permissions](https://developer.brigg.app/developers/permissions) determine which operations your integration can invoke. --- # Integrations Explore integrations resources and their published operations. ## Resources - [API connections](https://developer.brigg.app/developers/reference/areas/integrations/api-connections) — 2 operations - [API keys](https://developer.brigg.app/developers/reference/areas/integrations/api-keys) — 2 operations - [External integrations](https://developer.brigg.app/developers/reference/areas/integrations/external-integrations) — 1 operation - [MCP servers](https://developer.brigg.app/developers/reference/areas/integrations/mcp-servers) — 2 operations - [Record imports](https://developer.brigg.app/developers/reference/areas/integrations/record-imports) — 5 operations Choose a resource to explore its operations and access requirements. [Credential permissions](https://developer.brigg.app/developers/permissions) determine which operations your integration can invoke. --- # Meetings Explore meetings resources and their published operations. ## Resources - [Booking](https://developer.brigg.app/developers/reference/areas/meetings/booking) — 5 operations - [Calendar](https://developer.brigg.app/developers/reference/areas/meetings/calendar) — 12 operations - [Dictionary entry](https://developer.brigg.app/developers/reference/areas/meetings/dictionary-entry) — 6 operations - [Meeting](https://developer.brigg.app/developers/reference/areas/meetings/meeting) — 14 operations - [Meeting agendas](https://developer.brigg.app/developers/reference/areas/meetings/meeting-agendas) — 1 operation - [Meeting finding](https://developer.brigg.app/developers/reference/areas/meetings/meeting-finding) — 6 operations - [Meeting note](https://developer.brigg.app/developers/reference/areas/meetings/meeting-note) — 3 operations - [Meeting template](https://developer.brigg.app/developers/reference/areas/meetings/meeting-template) — 7 operations - [Summary delivery](https://developer.brigg.app/developers/reference/areas/meetings/summary-delivery) — 1 operation Choose a resource to explore its operations and access requirements. [Credential permissions](https://developer.brigg.app/developers/permissions) determine which operations your integration can invoke. --- # Booking Explore booking resources and their published operations. ## Resources - [Booking links](https://developer.brigg.app/developers/reference/areas/meetings/booking/booking-links) — 4 operations - [Bookings](https://developer.brigg.app/developers/reference/areas/meetings/booking/bookings) — 1 operation Choose a resource to explore its operations and access requirements. [Credential permissions](https://developer.brigg.app/developers/permissions) determine which operations your integration can invoke. --- # Calendar Explore calendar resources and their published operations. ## Resources - [Calendar connections](https://developer.brigg.app/developers/reference/areas/meetings/calendar/calendar-connections) — 2 operations - [Calendar event](https://developer.brigg.app/developers/reference/areas/meetings/calendar/calendar-event) — 6 operations - [Connected events](https://developer.brigg.app/developers/reference/areas/meetings/calendar/connected-events) — 3 operations - [Meeting](https://developer.brigg.app/developers/reference/areas/meetings/calendar/meeting) — 1 operation Choose a resource to explore its operations and access requirements. [Credential permissions](https://developer.brigg.app/developers/permissions) determine which operations your integration can invoke. --- # Newsletters Explore newsletters resources and their published operations. ## Resources - [Newsletter issues](https://developer.brigg.app/developers/reference/areas/newsletters/newsletter-issues) — 5 operations - [Newsletter settings](https://developer.brigg.app/developers/reference/areas/newsletters/newsletter-settings) — 2 operations - [Schedules](https://developer.brigg.app/developers/reference/areas/newsletters/schedules) — 5 operations Choose a resource to explore its operations and access requirements. [Credential permissions](https://developer.brigg.app/developers/permissions) determine which operations your integration can invoke. --- # Signing Explore signing resources and their published operations. ## Resources - [Signing requests](https://developer.brigg.app/developers/reference/areas/signing/signing-requests) — 8 operations Choose a resource to explore its operations and access requirements. [Credential permissions](https://developer.brigg.app/developers/permissions) determine which operations your integration can invoke. ## Workflow guides - [Send a PDF for signature](https://developer.brigg.app/developers/signing) — Upload a PDF, invite recipients, track their signatures and download the completed document. --- # Tasks Explore tasks resources and their published operations. ## Resources - [Task](https://developer.brigg.app/developers/reference/areas/tasks/task) — 6 operations Choose a resource to explore its operations and access requirements. [Credential permissions](https://developer.brigg.app/developers/permissions) determine which operations your integration can invoke. --- # Voice Explore voice resources and their published operations. ## Resources - [Bindings](https://developer.brigg.app/developers/reference/areas/voice/bindings) — 3 operations - [Inbox](https://developer.brigg.app/developers/reference/areas/voice/inbox) — 1 operation - [Voice tests](https://developer.brigg.app/developers/reference/areas/voice/voice-tests) — 4 operations Choose a resource to explore its operations and access requirements. [Credential permissions](https://developer.brigg.app/developers/permissions) determine which operations your integration can invoke. --- # Web analytics Explore web analytics resources and their published operations. ## Resources - [Website analytics](https://developer.brigg.app/developers/reference/areas/web-analytics/website-analytics) — 3 operations - [Workspace analytics](https://developer.brigg.app/developers/reference/areas/web-analytics/workspace-analytics) — 1 operation Choose a resource to explore its operations and access requirements. [Credential permissions](https://developer.brigg.app/developers/permissions) determine which operations your integration can invoke. --- # Webhooks Explore webhooks resources and their published operations. ## Resources - [Deliveries](https://developer.brigg.app/developers/reference/areas/webhooks/deliveries) — 2 operations - [Events](https://developer.brigg.app/developers/reference/areas/webhooks/events) — 1 operation - [Subscriptions](https://developer.brigg.app/developers/reference/areas/webhooks/subscriptions) — 5 operations Choose a resource to explore its operations and access requirements. [Credential permissions](https://developer.brigg.app/developers/permissions) determine which operations your integration can invoke. --- # Workspace Explore workspace resources and their published operations. ## Resources - [Agent network](https://developer.brigg.app/developers/reference/areas/workspace/agent-network) — 1 operation - [App catalog](https://developer.brigg.app/developers/reference/areas/workspace/app-catalog) — 3 operations - [Branding](https://developer.brigg.app/developers/reference/areas/workspace/branding) — 3 operations - [Domain claims](https://developer.brigg.app/developers/reference/areas/workspace/domain-claims) — 1 operation - [Email deliverability](https://developer.brigg.app/developers/reference/areas/workspace/email-deliverability) — 1 operation - [Members and access requests](https://developer.brigg.app/developers/reference/areas/workspace/members-and-access-requests) — 3 operations - [Playbooks](https://developer.brigg.app/developers/reference/areas/workspace/playbooks) — 1 operation - [Privacy settings](https://developer.brigg.app/developers/reference/areas/workspace/privacy-settings) — 2 operations - [Roles](https://developer.brigg.app/developers/reference/areas/workspace/roles) — 1 operation - [Workspace setup](https://developer.brigg.app/developers/reference/areas/workspace/workspace-setup) — 3 operations Choose a resource to explore its operations and access requirements. [Credential permissions](https://developer.brigg.app/developers/permissions) determine which operations your integration can invoke. --- # Rules Rules operations in Automation. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get rule](https://developer.brigg.app/developers/reference/automation/GetRule) · `automation.GetRule` | Read | Member delegation | | [List rules](https://developer.brigg.app/developers/reference/automation/ListRules) · `automation.ListRules` | Read | Member delegation | | [Delete rule](https://developer.brigg.app/developers/reference/automation/DeleteRule) · `automation.DeleteRule` | Write | Member delegation | | [Update rule](https://developer.brigg.app/developers/reference/automation/UpdateRule) · `automation.UpdateRule` | Write | Member delegation | Each operation page contains its request fields, result schema and accessed resources. --- # Billing Billing operations in Credits and usage. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get billing](https://developer.brigg.app/developers/reference/billing/GetBilling) · `billing.GetBilling` | Read | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Credits and usage Credits and usage operations in Credits and usage. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get storage usage](https://developer.brigg.app/developers/reference/billing/GetStorageUsage) · `billing.GetStorageUsage` | Read | API key | | [List credit ledger](https://developer.brigg.app/developers/reference/billing/ListCreditLedger) · `billing.ListCreditLedger` | Read | API key | | [List usage](https://developer.brigg.app/developers/reference/billing/ListUsage) · `billing.ListUsage` | Read | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Contact channel Contact channel operations in Customer service. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get contact channel](https://developer.brigg.app/developers/reference/support/GetContactChannel) · `support.GetContactChannel` | Read | API key | | [List contact channels](https://developer.brigg.app/developers/reference/support/ListContactChannels) · `support.ListContactChannels` | Read | API key | | [Create contact channel](https://developer.brigg.app/developers/reference/support/CreateContactChannel) · `support.CreateContactChannel` | Write | API key | | [Delete contact channel](https://developer.brigg.app/developers/reference/support/DeleteContactChannel) · `support.DeleteContactChannel` | Write | API key | | [Update contact channel](https://developer.brigg.app/developers/reference/support/UpdateContactChannel) · `support.UpdateContactChannel` | Write | API key | | [Upsert contact channel](https://developer.brigg.app/developers/reference/support/UpsertContactChannel) · `support.UpsertContactChannel` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Conversation Conversation operations in Customer service. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get conversation](https://developer.brigg.app/developers/reference/support/GetConversation) · `support.GetConversation` | Read | API key | | [List conversations](https://developer.brigg.app/developers/reference/support/ListConversations) · `support.ListConversations` | Read | API key | | [Create conversation](https://developer.brigg.app/developers/reference/support/CreateConversation) · `support.CreateConversation` | Write | API key | | [Delete conversation](https://developer.brigg.app/developers/reference/support/DeleteConversation) · `support.DeleteConversation` | Write | API key | | [Update conversation](https://developer.brigg.app/developers/reference/support/UpdateConversation) · `support.UpdateConversation` | Write | API key | | [Upsert conversation](https://developer.brigg.app/developers/reference/support/UpsertConversation) · `support.UpsertConversation` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Inbox Inbox operations in Customer service. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get inbox](https://developer.brigg.app/developers/reference/support/GetInbox) · `support.GetInbox` | Read | API key | | [List inbox channels](https://developer.brigg.app/developers/reference/support/ListInboxChannels) · `support.ListInboxChannels` | Read | API key | | [List inboxes](https://developer.brigg.app/developers/reference/support/ListInboxes) · `support.ListInboxes` | Read | API key | | [List inbox support addresses](https://developer.brigg.app/developers/reference/support/ListInboxSupportAddresses) · `support.ListInboxSupportAddresses` | Read | API key | | [Create inbox](https://developer.brigg.app/developers/reference/support/CreateInbox) · `support.CreateInbox` | Write | API key | | [Delete inbox](https://developer.brigg.app/developers/reference/support/DeleteInbox) · `support.DeleteInbox` | Write | API key | | [Update inbox](https://developer.brigg.app/developers/reference/support/UpdateInbox) · `support.UpdateInbox` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Inbox message Inbox message operations in Customer service. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get inbox message](https://developer.brigg.app/developers/reference/support/GetInboxMessage) · `support.GetInboxMessage` | Read | API key | | [List inbox messages](https://developer.brigg.app/developers/reference/support/ListInboxMessages) · `support.ListInboxMessages` | Read | API key | | [Add inbox note](https://developer.brigg.app/developers/reference/support/AddInboxNote) · `support.AddInboxNote` | Write | Member delegation | Each operation page contains its request fields, result schema and accessed resources. --- # Phone numbers Phone numbers operations in Customer service. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get phone number quote](https://developer.brigg.app/developers/reference/support/GetPhoneNumberQuote) · `support.GetPhoneNumberQuote` | Read | API key | | [List phone numbers](https://developer.brigg.app/developers/reference/support/ListPhoneNumbers) · `support.ListPhoneNumbers` | Read | Member delegation | | [Configure phone number](https://developer.brigg.app/developers/reference/support/ConfigurePhoneNumber) · `support.ConfigurePhoneNumber` | Write | API key | | [Set phone number enabled](https://developer.brigg.app/developers/reference/support/SetPhoneNumberEnabled) · `support.SetPhoneNumberEnabled` | Write | API key | | [Set phone number usage](https://developer.brigg.app/developers/reference/support/SetPhoneNumberUsage) · `support.SetPhoneNumberUsage` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Replies Replies operations in Customer service. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Generate inbox reply](https://developer.brigg.app/developers/reference/support/GenerateInboxReply) · `support.GenerateInboxReply` | Write | Member delegation | Each operation page contains its request fields, result schema and accessed resources. --- # Support addresses Support addresses operations in Customer service. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Add inbox support address](https://developer.brigg.app/developers/reference/support/AddInboxSupportAddress) · `support.AddInboxSupportAddress` | Write | API key | | [Remove inbox support address](https://developer.brigg.app/developers/reference/support/RemoveInboxSupportAddress) · `support.RemoveInboxSupportAddress` | Write | API key | | [Resend inbox support address test](https://developer.brigg.app/developers/reference/support/ResendInboxSupportAddressTest) · `support.ResendInboxSupportAddressTest` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Briefs Briefs operations in Customers. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Add brief context](https://developer.brigg.app/developers/reference/customers/AddBriefContext) · `customers.AddBriefContext` | Write | Member delegation | | [Generate brief](https://developer.brigg.app/developers/reference/customers/GenerateBrief) · `customers.GenerateBrief` | Write | Member delegation | | [Remove brief context](https://developer.brigg.app/developers/reference/customers/RemoveBriefContext) · `customers.RemoveBriefContext` | Write | Member delegation | | [Run brief action](https://developer.brigg.app/developers/reference/customers/RunBriefAction) · `customers.RunBriefAction` | Write | Member delegation | Each operation page contains its request fields, result schema and accessed resources. --- # Company Company operations in Customers. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get company](https://developer.brigg.app/developers/reference/customers/GetCompany) · `customers.GetCompany` | Read | API key | | [Get company registry facts](https://developer.brigg.app/developers/reference/customers/GetCompanyRegistryFacts) · `customers.GetCompanyRegistryFacts` | Read | Member delegation | | [List companies](https://developer.brigg.app/developers/reference/customers/ListCompanies) · `customers.ListCompanies` | Read | API key | | [Create company](https://developer.brigg.app/developers/reference/customers/CreateCompany) · `customers.CreateCompany` | Write | API key | | [Delete company](https://developer.brigg.app/developers/reference/customers/DeleteCompany) · `customers.DeleteCompany` | Write | API key | | [Update company](https://developer.brigg.app/developers/reference/customers/UpdateCompany) · `customers.UpdateCompany` | Write | API key | | [Upsert company](https://developer.brigg.app/developers/reference/customers/UpsertCompany) · `customers.UpsertCompany` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Company discovery Company discovery operations in Customers. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get indexed company](https://developer.brigg.app/developers/reference/customers/GetIndexedCompany) · `customers.GetIndexedCompany` | Read | API key | | [Search company index](https://developer.brigg.app/developers/reference/customers/SearchCompanyIndex) · `customers.SearchCompanyIndex` | Read | API key | | [Search person roles](https://developer.brigg.app/developers/reference/customers/SearchPersonRoles) · `customers.SearchPersonRoles` | Read | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Deal Deal operations in Customers. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get deal](https://developer.brigg.app/developers/reference/customers/GetDeal) · `customers.GetDeal` | Read | API key | | [List deals](https://developer.brigg.app/developers/reference/customers/ListDeals) · `customers.ListDeals` | Read | API key | | [Create deal](https://developer.brigg.app/developers/reference/customers/CreateDeal) · `customers.CreateDeal` | Write | API key | | [Delete deal](https://developer.brigg.app/developers/reference/customers/DeleteDeal) · `customers.DeleteDeal` | Write | API key | | [Update deal](https://developer.brigg.app/developers/reference/customers/UpdateDeal) · `customers.UpdateDeal` | Write | API key | | [Upsert deal](https://developer.brigg.app/developers/reference/customers/UpsertDeal) · `customers.UpsertDeal` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Email message Email message operations in Customers. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get email message](https://developer.brigg.app/developers/reference/customers/GetEmailMessage) · `customers.GetEmailMessage` | Read | API key | | [List email messages](https://developer.brigg.app/developers/reference/customers/ListEmailMessages) · `customers.ListEmailMessages` | Read | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Imports and HubSpot Imports and HubSpot operations in Customers. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get CRM import run](https://developer.brigg.app/developers/reference/customers/GetCrmImportRun) · `customers.GetCrmImportRun` | Read | API key | | [Get CRM import status](https://developer.brigg.app/developers/reference/customers/GetCrmImportStatus) · `customers.GetCrmImportStatus` | Read | API key | | [Preview contact import](https://developer.brigg.app/developers/reference/customers/PreviewContactImport) · `customers.PreviewContactImport` | Read | API key | | [Preview CRM import](https://developer.brigg.app/developers/reference/customers/PreviewCrmImport) · `customers.PreviewCrmImport` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Note Note operations in Customers. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get note](https://developer.brigg.app/developers/reference/customers/GetNote) · `customers.GetNote` | Read | API key | | [List notes](https://developer.brigg.app/developers/reference/customers/ListNotes) · `customers.ListNotes` | Read | API key | | [Create note](https://developer.brigg.app/developers/reference/customers/CreateNote) · `customers.CreateNote` | Write | API key | | [Delete note](https://developer.brigg.app/developers/reference/customers/DeleteNote) · `customers.DeleteNote` | Write | API key | | [Update note](https://developer.brigg.app/developers/reference/customers/UpdateNote) · `customers.UpdateNote` | Write | API key | | [Upsert note](https://developer.brigg.app/developers/reference/customers/UpsertNote) · `customers.UpsertNote` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Person Person operations in Customers. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get person](https://developer.brigg.app/developers/reference/customers/GetPerson) · `customers.GetPerson` | Read | API key | | [List people](https://developer.brigg.app/developers/reference/customers/ListPeople) · `customers.ListPeople` | Read | API key | | [Create person](https://developer.brigg.app/developers/reference/customers/CreatePerson) · `customers.CreatePerson` | Write | API key | | [Delete person](https://developer.brigg.app/developers/reference/customers/DeletePerson) · `customers.DeletePerson` | Write | API key | | [Update person](https://developer.brigg.app/developers/reference/customers/UpdatePerson) · `customers.UpdatePerson` | Write | API key | | [Upsert person](https://developer.brigg.app/developers/reference/customers/UpsertPerson) · `customers.UpsertPerson` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Product Product operations in Customers. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get product](https://developer.brigg.app/developers/reference/customers/GetProduct) · `customers.GetProduct` | Read | API key | | [List products](https://developer.brigg.app/developers/reference/customers/ListProducts) · `customers.ListProducts` | Read | API key | | [Create product](https://developer.brigg.app/developers/reference/customers/CreateProduct) · `customers.CreateProduct` | Write | API key | | [Delete product](https://developer.brigg.app/developers/reference/customers/DeleteProduct) · `customers.DeleteProduct` | Write | API key | | [Update product](https://developer.brigg.app/developers/reference/customers/UpdateProduct) · `customers.UpdateProduct` | Write | API key | | [Upsert product](https://developer.brigg.app/developers/reference/customers/UpsertProduct) · `customers.UpsertProduct` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Record enrichment Record enrichment operations in Customers. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Search registered companies](https://developer.brigg.app/developers/reference/customers/SearchRegisteredCompanies) · `customers.SearchRegisteredCompanies` | Read | Member delegation | | [Enrich record](https://developer.brigg.app/developers/reference/customers/EnrichRecord) · `customers.EnrichRecord` | Write | Member delegation | Each operation page contains its request fields, result schema and accessed resources. --- # Sales pipeline Sales pipeline operations in Customers. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get sales pipeline](https://developer.brigg.app/developers/reference/customers/GetSalesPipeline) · `customers.GetSalesPipeline` | Read | API key | | [List sales pipelines](https://developer.brigg.app/developers/reference/customers/ListSalesPipelines) · `customers.ListSalesPipelines` | Read | API key | | [Create sales pipeline](https://developer.brigg.app/developers/reference/customers/CreateSalesPipeline) · `customers.CreateSalesPipeline` | Write | API key | | [Delete sales pipeline](https://developer.brigg.app/developers/reference/customers/DeleteSalesPipeline) · `customers.DeleteSalesPipeline` | Write | API key | | [Update sales pipeline](https://developer.brigg.app/developers/reference/customers/UpdateSalesPipeline) · `customers.UpdateSalesPipeline` | Write | API key | | [Upsert sales pipeline](https://developer.brigg.app/developers/reference/customers/UpsertSalesPipeline) · `customers.UpsertSalesPipeline` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Tags Tags operations in Customers. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [List tags](https://developer.brigg.app/developers/reference/customers/ListTags) · `customers.ListTags` | Read | API key | | [List tag vocabularies](https://developer.brigg.app/developers/reference/customers/ListTagVocabularies) · `customers.ListTagVocabularies` | Read | API key | | [Create tag](https://developer.brigg.app/developers/reference/customers/CreateTag) · `customers.CreateTag` | Write | API key | | [Delete tag](https://developer.brigg.app/developers/reference/customers/DeleteTag) · `customers.DeleteTag` | Write | API key | | [Update tag](https://developer.brigg.app/developers/reference/customers/UpdateTag) · `customers.UpdateTag` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Apps and bundles Apps and bundles operations in Documents. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Copy bundle](https://developer.brigg.app/developers/reference/documents/CopyBundle) · `documents.CopyBundle` | Write | Member delegation | | [Create app](https://developer.brigg.app/developers/reference/documents/CreateApp) · `documents.CreateApp` | Write | Member delegation | | [Delete content](https://developer.brigg.app/developers/reference/documents/DeleteBundle) · `documents.DeleteBundle` | Write | Member delegation | | [Rename content](https://developer.brigg.app/developers/reference/documents/RenameBundle) · `documents.RenameBundle` | Write | Member delegation | Each operation page contains its request fields, result schema and accessed resources. --- # Attachments Attachments operations in Documents. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Attach document](https://developer.brigg.app/developers/reference/documents/AttachDocument) · `documents.AttachDocument` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Document templates Document templates operations in Documents. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get Word fill job](https://developer.brigg.app/developers/reference/documents/GetWordFillJob) · `documents.GetWordFillJob` | Read | Member delegation | | [List document template fields](https://developer.brigg.app/developers/reference/documents/ListDocumentTemplateFields) · `documents.ListDocumentTemplateFields` | Read | Member delegation | | [Add document template field](https://developer.brigg.app/developers/reference/documents/AddDocumentTemplateField) · `documents.AddDocumentTemplateField` | Write | Member delegation | | [Delete document template](https://developer.brigg.app/developers/reference/documents/DeleteDocumentTemplate) · `documents.DeleteDocumentTemplate` | Write | Member delegation | | [Fill Word template](https://developer.brigg.app/developers/reference/documents/FillWordTemplate) · `documents.FillWordTemplate` | Write | Member delegation | | [Install document template](https://developer.brigg.app/developers/reference/documents/InstallDocumentTemplate) · `documents.InstallDocumentTemplate` | Write | Member delegation | | [Remove document template field](https://developer.brigg.app/developers/reference/documents/RemoveDocumentTemplateField) · `documents.RemoveDocumentTemplateField` | Write | Member delegation | | [Update document template](https://developer.brigg.app/developers/reference/documents/UpdateDocumentTemplate) · `documents.UpdateDocumentTemplate` | Write | Member delegation | | [Update document template field](https://developer.brigg.app/developers/reference/documents/UpdateDocumentTemplateField) · `documents.UpdateDocumentTemplateField` | Write | Member delegation | Each operation page contains its request fields, result schema and accessed resources. --- # Documents Documents operations in Documents. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get document](https://developer.brigg.app/developers/reference/documents/GetDocument) · `documents.GetDocument` | Read | API key | | [List documents](https://developer.brigg.app/developers/reference/documents/ListDocuments) · `documents.ListDocuments` | Read | API key | | [Search document content](https://developer.brigg.app/developers/reference/documents/SearchDocumentContent) · `documents.SearchDocumentContent` | Read | API key | | [Search documents](https://developer.brigg.app/developers/reference/documents/SearchDocuments) · `documents.SearchDocuments` | Read | API key | | [Delete document](https://developer.brigg.app/developers/reference/documents/DeleteDocument) · `documents.DeleteDocument` | Write | API key | | [Detach document](https://developer.brigg.app/developers/reference/documents/DetachDocument) · `documents.DetachDocument` | Write | API key | | [Export document](https://developer.brigg.app/developers/reference/documents/ExportDocument) · `documents.ExportDocument` | Write | API key | | [Move document](https://developer.brigg.app/developers/reference/documents/MoveDocument) · `documents.MoveDocument` | Write | API key | | [Rename document](https://developer.brigg.app/developers/reference/documents/RenameDocument) · `documents.RenameDocument` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Files and uploads Files and uploads operations in Documents. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get file](https://developer.brigg.app/developers/reference/documents/GetFile) · `documents.GetFile` | Read | API key | | [Get file download](https://developer.brigg.app/developers/reference/documents/GetFileDownload) · `documents.GetFileDownload` | Read | API key | | [Get upload](https://developer.brigg.app/developers/reference/documents/GetUpload) · `documents.GetUpload` | Read | API key | | [Get upload part](https://developer.brigg.app/developers/reference/documents/GetUploadPart) · `documents.GetUploadPart` | Read | API key | | [Cancel upload](https://developer.brigg.app/developers/reference/documents/CancelUpload) · `documents.CancelUpload` | Write | API key | | [Complete upload](https://developer.brigg.app/developers/reference/documents/CompleteUpload) · `documents.CompleteUpload` | Write | API key | | [Create upload](https://developer.brigg.app/developers/reference/documents/CreateUpload) · `documents.CreateUpload` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Folders Folders operations in Documents. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Create folder](https://developer.brigg.app/developers/reference/documents/CreateFolder) · `documents.CreateFolder` | Write | API key | | [Delete folder](https://developer.brigg.app/developers/reference/documents/DeleteFolder) · `documents.DeleteFolder` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Sharing Sharing operations in Documents. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get bundle sharing](https://developer.brigg.app/developers/reference/documents/GetBundleSharing) · `documents.GetBundleSharing` | Read | Member delegation | | [Revoke document share](https://developer.brigg.app/developers/reference/documents/RevokeDocumentShare) · `documents.RevokeDocumentShare` | Write | Member delegation | | [Share document](https://developer.brigg.app/developers/reference/documents/ShareDocument) · `documents.ShareDocument` | Write | Member delegation | Each operation page contains its request fields, result schema and accessed resources. --- # Text documents Text documents operations in Documents. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get text document content](https://developer.brigg.app/developers/reference/documents/GetTextDocumentContent) · `documents.GetTextDocumentContent` | Read | API key | | [Get text document version](https://developer.brigg.app/developers/reference/documents/GetTextDocumentVersion) · `documents.GetTextDocumentVersion` | Read | API key | | [List text document shares](https://developer.brigg.app/developers/reference/documents/ListTextDocumentShares) · `documents.ListTextDocumentShares` | Read | Member delegation | | [List text document versions](https://developer.brigg.app/developers/reference/documents/ListTextDocumentVersions) · `documents.ListTextDocumentVersions` | Read | API key | | [Read text document](https://developer.brigg.app/developers/reference/documents/ReadTextDocument) · `documents.ReadTextDocument` | Read | API key | | [Checkpoint text document](https://developer.brigg.app/developers/reference/documents/CheckpointTextDocument) · `documents.CheckpointTextDocument` | Write | API key | | [Convert document to text document](https://developer.brigg.app/developers/reference/documents/ConvertDocumentToTextDocument) · `documents.ConvertDocumentToTextDocument` | Write | API key | | [Create text document](https://developer.brigg.app/developers/reference/documents/CreateTextDocument) · `documents.CreateTextDocument` | Write | API key | | [Edit text document](https://developer.brigg.app/developers/reference/documents/EditTextDocument) · `documents.EditTextDocument` | Write | API key | | [Replace text document](https://developer.brigg.app/developers/reference/documents/ReplaceTextDocument) · `documents.ReplaceTextDocument` | Write | API key | | [Revert text document](https://developer.brigg.app/developers/reference/documents/RevertTextDocument) · `documents.RevertTextDocument` | Write | API key | | [Revoke text document share](https://developer.brigg.app/developers/reference/documents/RevokeTextDocumentShare) · `documents.RevokeTextDocumentShare` | Write | Member delegation | | [Share text document](https://developer.brigg.app/developers/reference/documents/ShareTextDocument) · `documents.ShareTextDocument` | Write | Member delegation | Each operation page contains its request fields, result schema and accessed resources. --- # DNS records DNS records operations in Domains. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [List DNS records](https://developer.brigg.app/developers/reference/domains/ListDnsRecords) · `domains.ListDnsRecords` | Read | Member delegation | | [Delete DNS record](https://developer.brigg.app/developers/reference/domains/DeleteDnsRecord) · `domains.DeleteDnsRecord` | Write | API key | | [Set DNS record](https://developer.brigg.app/developers/reference/domains/SetDnsRecord) · `domains.SetDnsRecord` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Domains Domains operations in Domains. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [List hosted domains](https://developer.brigg.app/developers/reference/domains/ListHostedDomains) · `domains.ListHostedDomains` | Read | Member delegation | | [Search domains](https://developer.brigg.app/developers/reference/domains/SearchDomains) · `domains.SearchDomains` | Read | Member delegation | | [Dismiss failed domain](https://developer.brigg.app/developers/reference/domains/DismissFailedDomain) · `domains.DismissFailedDomain` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Registrant details Registrant details operations in Domains. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get domain registrant](https://developer.brigg.app/developers/reference/domains/GetDomainRegistrant) · `domains.GetDomainRegistrant` | Read | Member delegation | | [Save domain registrant](https://developer.brigg.app/developers/reference/domains/SaveDomainRegistrant) · `domains.SaveDomainRegistrant` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Website domains Website domains operations in Domains. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [List site domains](https://developer.brigg.app/developers/reference/domains/ListSiteDomains) · `domains.ListSiteDomains` | Read | Member delegation | | [Add site domain](https://developer.brigg.app/developers/reference/domains/AddSiteDomain) · `domains.AddSiteDomain` | Write | Member delegation | | [Connect domain to site](https://developer.brigg.app/developers/reference/domains/ConnectDomainToSite) · `domains.ConnectDomainToSite` | Write | API key | | [Disconnect domain from site](https://developer.brigg.app/developers/reference/domains/DisconnectDomainFromSite) · `domains.DisconnectDomainFromSite` | Write | API key | | [Remove site domain](https://developer.brigg.app/developers/reference/domains/RemoveSiteDomain) · `domains.RemoveSiteDomain` | Write | Member delegation | | [Retry site domain](https://developer.brigg.app/developers/reference/domains/RetrySiteDomain) · `domains.RetrySiteDomain` | Write | Member delegation | Each operation page contains its request fields, result schema and accessed resources. --- # Images Images operations in Images. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Generate image](https://developer.brigg.app/developers/reference/images/GenerateImage) · `images.GenerateImage` | Write | Member delegation | Each operation page contains its request fields, result schema and accessed resources. --- # API connections API connections operations in Integrations. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [List API connections](https://developer.brigg.app/developers/reference/integrations/ListApiConnections) · `integrations.ListApiConnections` | Read | API key | | [Delete API connection](https://developer.brigg.app/developers/reference/integrations/DeleteApiConnection) · `integrations.DeleteApiConnection` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # API keys API keys operations in Integrations. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [List API keys](https://developer.brigg.app/developers/reference/integrations/ListApiKeys) · `integrations.ListApiKeys` | Read | API key | | [Revoke API key](https://developer.brigg.app/developers/reference/integrations/RevokeApiKey) · `integrations.RevokeApiKey` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # External integrations External integrations operations in Integrations. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [List integrations](https://developer.brigg.app/developers/reference/integrations/ListIntegrations) · `integrations.ListIntegrations` | Read | API key | Each operation page contains its request fields, result schema and accessed resources. --- # MCP servers MCP servers operations in Integrations. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [List MCP servers](https://developer.brigg.app/developers/reference/integrations/ListMcpServers) · `integrations.ListMcpServers` | Read | API key | | [Delete MCP server](https://developer.brigg.app/developers/reference/integrations/DeleteMcpServer) · `integrations.DeleteMcpServer` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Record imports Record imports operations in Integrations. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get record import](https://developer.brigg.app/developers/reference/integrations/GetRecordImport) · `integrations.GetRecordImport` | Read | API key | | [List record import rows](https://developer.brigg.app/developers/reference/integrations/ListRecordImportRows) · `integrations.ListRecordImportRows` | Read | API key | | [Cancel record import](https://developer.brigg.app/developers/reference/integrations/CancelRecordImport) · `integrations.CancelRecordImport` | Write | API key | | [Resume record import](https://developer.brigg.app/developers/reference/integrations/ResumeRecordImport) · `integrations.ResumeRecordImport` | Write | API key | | [Start record import](https://developer.brigg.app/developers/reference/integrations/StartRecordImport) · `integrations.StartRecordImport` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Dictionary entry Dictionary entry operations in Meetings. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get dictionary entry](https://developer.brigg.app/developers/reference/meetings/GetDictionaryEntry) · `meetings.GetDictionaryEntry` | Read | API key | | [List dictionary entries](https://developer.brigg.app/developers/reference/meetings/ListDictionaryEntries) · `meetings.ListDictionaryEntries` | Read | API key | | [Create dictionary entry](https://developer.brigg.app/developers/reference/meetings/CreateDictionaryEntry) · `meetings.CreateDictionaryEntry` | Write | API key | | [Delete dictionary entry](https://developer.brigg.app/developers/reference/meetings/DeleteDictionaryEntry) · `meetings.DeleteDictionaryEntry` | Write | API key | | [Update dictionary entry](https://developer.brigg.app/developers/reference/meetings/UpdateDictionaryEntry) · `meetings.UpdateDictionaryEntry` | Write | API key | | [Upsert dictionary entry](https://developer.brigg.app/developers/reference/meetings/UpsertDictionaryEntry) · `meetings.UpsertDictionaryEntry` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Meeting Meeting operations in Meetings. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get meeting](https://developer.brigg.app/developers/reference/meetings/GetMeeting) · `meetings.GetMeeting` | Read | API key | | [Get recently ended meeting](https://developer.brigg.app/developers/reference/meetings/GetRecentlyEndedMeeting) · `meetings.GetRecentlyEndedMeeting` | Read | Member delegation | | [List meetings](https://developer.brigg.app/developers/reference/meetings/ListMeetings) · `meetings.ListMeetings` | Read | API key | | [Read meeting transcript](https://developer.brigg.app/developers/reference/meetings/ReadMeetingTranscript) · `meetings.ReadMeetingTranscript` | Read | Member delegation | | [Apply meeting template summary](https://developer.brigg.app/developers/reference/meetings/ApplyMeetingTemplateSummary) · `meetings.ApplyMeetingTemplateSummary` | Write | Member delegation | | [Create meeting](https://developer.brigg.app/developers/reference/meetings/CreateMeeting) · `meetings.CreateMeeting` | Write | API key | | [Delete meeting](https://developer.brigg.app/developers/reference/meetings/DeleteMeeting) · `meetings.DeleteMeeting` | Write | API key | | [Delete meeting transcript](https://developer.brigg.app/developers/reference/meetings/DeleteMeetingTranscript) · `meetings.DeleteMeetingTranscript` | Write | Member delegation | | [Link meeting calendar event](https://developer.brigg.app/developers/reference/meetings/LinkMeetingCalendarEvent) · `meetings.LinkMeetingCalendarEvent` | Write | Member delegation | | [Refresh meeting summary](https://developer.brigg.app/developers/reference/meetings/RefreshMeetingSummary) · `meetings.RefreshMeetingSummary` | Write | Member delegation | | [Set meeting sharing](https://developer.brigg.app/developers/reference/meetings/SetMeetingSharing) · `meetings.SetMeetingSharing` | Write | Member delegation | | [Set speaker names](https://developer.brigg.app/developers/reference/meetings/SetSpeakerNames) · `meetings.SetSpeakerNames` | Write | Member delegation | | [Update meeting](https://developer.brigg.app/developers/reference/meetings/UpdateMeeting) · `meetings.UpdateMeeting` | Write | API key | | [Upsert meeting](https://developer.brigg.app/developers/reference/meetings/UpsertMeeting) · `meetings.UpsertMeeting` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Meeting agendas Meeting agendas operations in Meetings. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Generate meeting agenda](https://developer.brigg.app/developers/reference/meetings/GenerateMeetingAgenda) · `meetings.GenerateMeetingAgenda` | Write | Member delegation | Each operation page contains its request fields, result schema and accessed resources. --- # Meeting finding Meeting finding operations in Meetings. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get meeting finding](https://developer.brigg.app/developers/reference/meetings/GetMeetingFinding) · `meetings.GetMeetingFinding` | Read | API key | | [List meeting findings](https://developer.brigg.app/developers/reference/meetings/ListMeetingFindings) · `meetings.ListMeetingFindings` | Read | API key | | [Create meeting finding](https://developer.brigg.app/developers/reference/meetings/CreateMeetingFinding) · `meetings.CreateMeetingFinding` | Write | API key | | [Delete meeting finding](https://developer.brigg.app/developers/reference/meetings/DeleteMeetingFinding) · `meetings.DeleteMeetingFinding` | Write | API key | | [Update meeting finding](https://developer.brigg.app/developers/reference/meetings/UpdateMeetingFinding) · `meetings.UpdateMeetingFinding` | Write | API key | | [Upsert meeting finding](https://developer.brigg.app/developers/reference/meetings/UpsertMeetingFinding) · `meetings.UpsertMeetingFinding` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Meeting note Meeting note operations in Meetings. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get meeting note](https://developer.brigg.app/developers/reference/meetings/GetMeetingNote) · `meetings.GetMeetingNote` | Read | Member delegation | | [List meeting notes](https://developer.brigg.app/developers/reference/meetings/ListMeetingNotes) · `meetings.ListMeetingNotes` | Read | Member delegation | | [Save meeting note](https://developer.brigg.app/developers/reference/meetings/SaveMeetingNote) · `meetings.SaveMeetingNote` | Write | Member delegation | Each operation page contains its request fields, result schema and accessed resources. --- # Meeting template Meeting template operations in Meetings. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get meeting template](https://developer.brigg.app/developers/reference/meetings/GetMeetingTemplate) · `meetings.GetMeetingTemplate` | Read | API key | | [List meeting templates](https://developer.brigg.app/developers/reference/meetings/ListMeetingTemplates) · `meetings.ListMeetingTemplates` | Read | API key | | [Create meeting template](https://developer.brigg.app/developers/reference/meetings/CreateMeetingTemplate) · `meetings.CreateMeetingTemplate` | Write | API key | | [Delete meeting template](https://developer.brigg.app/developers/reference/meetings/DeleteMeetingTemplate) · `meetings.DeleteMeetingTemplate` | Write | API key | | [Set meeting template sharing](https://developer.brigg.app/developers/reference/meetings/SetMeetingTemplateSharing) · `meetings.SetMeetingTemplateSharing` | Write | Member delegation | | [Update meeting template](https://developer.brigg.app/developers/reference/meetings/UpdateMeetingTemplate) · `meetings.UpdateMeetingTemplate` | Write | API key | | [Upsert meeting template](https://developer.brigg.app/developers/reference/meetings/UpsertMeetingTemplate) · `meetings.UpsertMeetingTemplate` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Summary delivery Summary delivery operations in Meetings. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Set meeting summary emails](https://developer.brigg.app/developers/reference/meetings/SetMeetingSummaryEmails) · `meetings.SetMeetingSummaryEmails` | Write | Member delegation | Each operation page contains its request fields, result schema and accessed resources. --- # Booking links Booking links operations in Booking. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [List booking links](https://developer.brigg.app/developers/reference/meetings/ListBookingLinks) · `meetings.ListBookingLinks` | Read | Member delegation | | [Create booking link](https://developer.brigg.app/developers/reference/meetings/CreateBookingLink) · `meetings.CreateBookingLink` | Write | Member delegation | | [Delete booking link](https://developer.brigg.app/developers/reference/meetings/DeleteBookingLink) · `meetings.DeleteBookingLink` | Write | Member delegation | | [Update booking link](https://developer.brigg.app/developers/reference/meetings/UpdateBookingLink) · `meetings.UpdateBookingLink` | Write | Member delegation | Each operation page contains its request fields, result schema and accessed resources. --- # Bookings Bookings operations in Booking. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Cancel booking](https://developer.brigg.app/developers/reference/meetings/CancelBooking) · `meetings.CancelBooking` | Write | Member delegation | Each operation page contains its request fields, result schema and accessed resources. --- # Calendar connections Calendar connections operations in Calendar. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [List calendar connections](https://developer.brigg.app/developers/reference/meetings/ListCalendarConnections) · `meetings.ListCalendarConnections` | Read | Member delegation | | [Select calendar](https://developer.brigg.app/developers/reference/meetings/SelectCalendar) · `meetings.SelectCalendar` | Write | Member delegation | Each operation page contains its request fields, result schema and accessed resources. --- # Calendar event Calendar event operations in Calendar. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get calendar event](https://developer.brigg.app/developers/reference/meetings/GetCalendarEvent) · `meetings.GetCalendarEvent` | Read | API key | | [List calendar events](https://developer.brigg.app/developers/reference/meetings/ListCalendarEvents) · `meetings.ListCalendarEvents` | Read | API key | | [Cancel calendar event](https://developer.brigg.app/developers/reference/meetings/CancelCalendarEvent) · `meetings.CancelCalendarEvent` | Write | API key | | [Create calendar event](https://developer.brigg.app/developers/reference/meetings/CreateCalendarEvent) · `meetings.CreateCalendarEvent` | Write | API key | | [Delete calendar event](https://developer.brigg.app/developers/reference/meetings/DeleteCalendarEvent) · `meetings.DeleteCalendarEvent` | Write | API key | | [Update calendar event](https://developer.brigg.app/developers/reference/meetings/UpdateCalendarEvent) · `meetings.UpdateCalendarEvent` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Connected events Connected events operations in Calendar. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Cancel connected calendar event](https://developer.brigg.app/developers/reference/meetings/CancelConnectedCalendarEvent) · `meetings.CancelConnectedCalendarEvent` | Write | Member delegation | | [Create connected calendar event](https://developer.brigg.app/developers/reference/meetings/CreateConnectedCalendarEvent) · `meetings.CreateConnectedCalendarEvent` | Write | Member delegation | | [Update connected calendar event](https://developer.brigg.app/developers/reference/meetings/UpdateConnectedCalendarEvent) · `meetings.UpdateConnectedCalendarEvent` | Write | Member delegation | Each operation page contains its request fields, result schema and accessed resources. --- # Meeting Meeting operations in Calendar. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Prepare meeting](https://developer.brigg.app/developers/reference/meetings/PrepareMeeting) · `meetings.PrepareMeeting` | Write | Member delegation | Each operation page contains its request fields, result schema and accessed resources. --- # Newsletter issues Newsletter issues operations in Newsletters. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get newsletter issue](https://developer.brigg.app/developers/reference/newsletters/GetNewsletterIssue) · `newsletters.GetNewsletterIssue` | Read | API key | | [List newsletter issues](https://developer.brigg.app/developers/reference/newsletters/ListNewsletterIssues) · `newsletters.ListNewsletterIssues` | Read | API key | | [Delete newsletter issue](https://developer.brigg.app/developers/reference/newsletters/DeleteNewsletterIssue) · `newsletters.DeleteNewsletterIssue` | Write | Member delegation | | [Save newsletter draft](https://developer.brigg.app/developers/reference/newsletters/SaveNewsletterDraft) · `newsletters.SaveNewsletterDraft` | Write | Member delegation | | [Send newsletter test email](https://developer.brigg.app/developers/reference/newsletters/SendNewsletterTestEmail) · `newsletters.SendNewsletterTestEmail` | Write | Member delegation | Each operation page contains its request fields, result schema and accessed resources. --- # Newsletter settings Newsletter settings operations in Newsletters. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get newsletter settings](https://developer.brigg.app/developers/reference/newsletters/GetNewsletterSettings) · `newsletters.GetNewsletterSettings` | Read | API key | | [Update newsletter settings](https://developer.brigg.app/developers/reference/newsletters/UpdateNewsletterSettings) · `newsletters.UpdateNewsletterSettings` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Schedules Schedules operations in Newsletters. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [List newsletter schedules](https://developer.brigg.app/developers/reference/newsletters/ListNewsletterSchedules) · `newsletters.ListNewsletterSchedules` | Read | API key | | [Create newsletter schedule](https://developer.brigg.app/developers/reference/newsletters/CreateNewsletterSchedule) · `newsletters.CreateNewsletterSchedule` | Write | Member delegation | | [Delete newsletter schedule](https://developer.brigg.app/developers/reference/newsletters/DeleteNewsletterSchedule) · `newsletters.DeleteNewsletterSchedule` | Write | Member delegation | | [Run newsletter schedule](https://developer.brigg.app/developers/reference/newsletters/RunNewsletterSchedule) · `newsletters.RunNewsletterSchedule` | Write | Member delegation | | [Update newsletter schedule](https://developer.brigg.app/developers/reference/newsletters/UpdateNewsletterSchedule) · `newsletters.UpdateNewsletterSchedule` | Write | Member delegation | Each operation page contains its request fields, result schema and accessed resources. --- # Signing requests Signing requests operations in Signing. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get signing document](https://developer.brigg.app/developers/reference/signing/GetSigningDocument) · `signing.GetSigningDocument` | Read | API key | | [Get signing request](https://developer.brigg.app/developers/reference/signing/GetSigningRequest) · `signing.GetSigningRequest` | Read | API key | | [List signing events](https://developer.brigg.app/developers/reference/signing/ListSigningEvents) · `signing.ListSigningEvents` | Read | API key | | [Cancel signing](https://developer.brigg.app/developers/reference/signing/CancelSigning) · `signing.CancelSigning` | Write | API key | | [Finalize signing](https://developer.brigg.app/developers/reference/signing/FinalizeSigning) · `signing.FinalizeSigning` | Write | API key | | [Remind signers](https://developer.brigg.app/developers/reference/signing/RemindSigners) · `signing.RemindSigners` | Write | API key | | [Request file signatures](https://developer.brigg.app/developers/reference/signing/RequestFileSignatures) · `signing.RequestFileSignatures` | Write | API key | | [Set signing deadline](https://developer.brigg.app/developers/reference/signing/SetSigningDeadline) · `signing.SetSigningDeadline` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Task Task operations in Tasks. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get task](https://developer.brigg.app/developers/reference/tasks/GetTask) · `tasks.GetTask` | Read | API key | | [List tasks](https://developer.brigg.app/developers/reference/tasks/ListTasks) · `tasks.ListTasks` | Read | API key | | [Create task](https://developer.brigg.app/developers/reference/tasks/CreateTask) · `tasks.CreateTask` | Write | API key | | [Delete task](https://developer.brigg.app/developers/reference/tasks/DeleteTask) · `tasks.DeleteTask` | Write | API key | | [Update task](https://developer.brigg.app/developers/reference/tasks/UpdateTask) · `tasks.UpdateTask` | Write | API key | | [Upsert task](https://developer.brigg.app/developers/reference/tasks/UpsertTask) · `tasks.UpsertTask` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Bindings Bindings operations in Voice. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Add voice binding](https://developer.brigg.app/developers/reference/voice/AddVoiceBinding) · `voice.AddVoiceBinding` | Write | Member delegation | | [Remove voice binding](https://developer.brigg.app/developers/reference/voice/RemoveVoiceBinding) · `voice.RemoveVoiceBinding` | Write | Member delegation | | [Update voice binding](https://developer.brigg.app/developers/reference/voice/UpdateVoiceBinding) · `voice.UpdateVoiceBinding` | Write | Member delegation | Each operation page contains its request fields, result schema and accessed resources. --- # Inbox Inbox operations in Voice. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get voice catalog](https://developer.brigg.app/developers/reference/voice/GetVoiceCatalog) · `voice.GetVoiceCatalog` | Read | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Voice tests Voice tests operations in Voice. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [End voice test](https://developer.brigg.app/developers/reference/voice/EndVoiceTest) · `voice.EndVoiceTest` | Write | Member delegation | | [Review voice test](https://developer.brigg.app/developers/reference/voice/ReviewVoiceTest) · `voice.ReviewVoiceTest` | Write | Member delegation | | [Run voice test turn](https://developer.brigg.app/developers/reference/voice/RunVoiceTestTurn) · `voice.RunVoiceTestTurn` | Write | Member delegation | | [Start voice test](https://developer.brigg.app/developers/reference/voice/StartVoiceTest) · `voice.StartVoiceTest` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Website analytics Website analytics operations in Web analytics. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get site analytics breakdown](https://developer.brigg.app/developers/reference/analytics/GetSiteAnalyticsBreakdown) · `analytics.GetSiteAnalyticsBreakdown` | Read | API key | | [Get site analytics realtime](https://developer.brigg.app/developers/reference/analytics/GetSiteAnalyticsRealtime) · `analytics.GetSiteAnalyticsRealtime` | Read | API key | | [Get site analytics summary](https://developer.brigg.app/developers/reference/analytics/GetSiteAnalyticsSummary) · `analytics.GetSiteAnalyticsSummary` | Read | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Workspace analytics Workspace analytics operations in Web analytics. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get workspace analytics summary](https://developer.brigg.app/developers/reference/analytics/GetWorkspaceAnalyticsSummary) · `analytics.GetWorkspaceAnalyticsSummary` | Read | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Deliveries Deliveries operations in Webhooks. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [List webhook deliveries](https://developer.brigg.app/developers/reference/webhooks/ListWebhookDeliveries) · `webhooks.ListWebhookDeliveries` | Read | API key | | [Replay webhook delivery](https://developer.brigg.app/developers/reference/webhooks/ReplayWebhookDelivery) · `webhooks.ReplayWebhookDelivery` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Events Events operations in Webhooks. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [List webhook events](https://developer.brigg.app/developers/reference/webhooks/ListWebhookEvents) · `webhooks.ListWebhookEvents` | Read | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Subscriptions Subscriptions operations in Webhooks. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [List webhooks](https://developer.brigg.app/developers/reference/webhooks/ListWebhooks) · `webhooks.ListWebhooks` | Read | API key | | [List webhook subscriptions](https://developer.brigg.app/developers/reference/webhooks/ListWebhookSubscriptions) · `webhooks.ListWebhookSubscriptions` | Read | API key | | [Prepare webhook](https://developer.brigg.app/developers/reference/webhooks/PrepareWebhook) · `webhooks.PrepareWebhook` | Read | API key | | [Delete webhook](https://developer.brigg.app/developers/reference/webhooks/DeleteWebhook) · `webhooks.DeleteWebhook` | Write | API key | | [Test webhook](https://developer.brigg.app/developers/reference/webhooks/TestWebhook) · `webhooks.TestWebhook` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Agent network Agent network operations in Workspace. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get agent network](https://developer.brigg.app/developers/reference/workspace/GetAgentNetwork) · `workspace.GetAgentNetwork` | Read | API key | Each operation page contains its request fields, result schema and accessed resources. --- # App catalog App catalog operations in Workspace. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [List apps](https://developer.brigg.app/developers/reference/workspace/ListApps) · `workspace.ListApps` | Read | API key | | [List bundles](https://developer.brigg.app/developers/reference/workspace/ListBundles) · `workspace.ListBundles` | Read | API key | | [List templates](https://developer.brigg.app/developers/reference/workspace/ListTemplates) · `workspace.ListTemplates` | Read | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Branding Branding operations in Workspace. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get branding](https://developer.brigg.app/developers/reference/workspace/GetBranding) · `workspace.GetBranding` | Read | API key | | [Refetch brand icon](https://developer.brigg.app/developers/reference/workspace/RefetchBrandIcon) · `workspace.RefetchBrandIcon` | Write | API key | | [Update branding](https://developer.brigg.app/developers/reference/workspace/UpdateBranding) · `workspace.UpdateBranding` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Domain claims Domain claims operations in Workspace. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [List domain claims](https://developer.brigg.app/developers/reference/workspace/ListDomainClaims) · `workspace.ListDomainClaims` | Read | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Email deliverability Email deliverability operations in Workspace. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get email deliverability](https://developer.brigg.app/developers/reference/workspace/GetEmailDeliverability) · `workspace.GetEmailDeliverability` | Read | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Members and access requests Members and access requests operations in Workspace. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [List colleagues](https://developer.brigg.app/developers/reference/workspace/ListColleagues) · `workspace.ListColleagues` | Read | API key | | [List join requests](https://developer.brigg.app/developers/reference/workspace/ListJoinRequests) · `workspace.ListJoinRequests` | Read | API key | | [List members](https://developer.brigg.app/developers/reference/workspace/ListMembers) · `workspace.ListMembers` | Read | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Playbooks Playbooks operations in Workspace. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Update personal playbook](https://developer.brigg.app/developers/reference/workspace/UpdatePersonalPlaybook) · `workspace.UpdatePersonalPlaybook` | Write | Member delegation | Each operation page contains its request fields, result schema and accessed resources. --- # Privacy settings Privacy settings operations in Workspace. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get privacy settings](https://developer.brigg.app/developers/reference/workspace/GetPrivacySettings) · `workspace.GetPrivacySettings` | Read | API key | | [Update privacy settings](https://developer.brigg.app/developers/reference/workspace/UpdatePrivacySettings) · `workspace.UpdatePrivacySettings` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Roles Roles operations in Workspace. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [List roles](https://developer.brigg.app/developers/reference/workspace/ListRoles) · `workspace.ListRoles` | Read | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Workspace setup Workspace setup operations in Workspace. ## Operations | Operation | Kind | Access | | --- | --- | --- | | [Get job](https://developer.brigg.app/developers/reference/workspace/GetJob) · `workspace.GetJob` | Read | Member delegation | | [Generate company profile](https://developer.brigg.app/developers/reference/workspace/GenerateCompanyProfile) · `workspace.GenerateCompanyProfile` | Write | API key | | [Update workspace profile](https://developer.brigg.app/developers/reference/workspace/UpdateWorkspaceProfile) · `workspace.UpdateWorkspaceProfile` | Write | API key | Each operation page contains its request fields, result schema and accessed resources. --- # Webhook event reference Payload fields for every supported webhook event. See [signature verification and delivery policy](https://developer.brigg.app/developers/webhooks) before processing events. ## meeting.completed A meeting has finished and its summary is ready. The existing contract includes the host's transcript. Contract version: **legacy**. ```json { "type": "object", "properties": { "event": { "type": "string", "const": "meeting.completed" }, "deliveryId": { "type": "string" }, "timestamp": { "type": "string", "format": "date-time" }, "webhookId": { "type": "string" }, "test": { "type": "boolean", "const": true }, "data": { "type": "object", "properties": { "meeting": { "type": "object", "properties": { "id": { "type": "string" }, "title": { "type": "string" }, "type": { "type": "string" }, "startedAt": { "type": "string", "format": "date-time" }, "endedAt": { "type": "string", "format": "date-time" }, "owner": { "type": "object", "properties": { "name": { "type": "string" }, "email": { "type": "string" }, "id": { "type": "string" } }, "required": [ "id" ], "additionalProperties": false }, "attendees": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string" }, "email": { "type": "string" } }, "additionalProperties": false } }, "summary": { "type": "string", "description": "Summary rendered as HTML." }, "transcript": { "type": "array", "items": { "type": "object", "properties": { "speaker": { "type": "string" }, "text": { "type": "string" }, "timestamp": { "type": "string" } }, "required": [ "text" ], "additionalProperties": false } } }, "required": [ "id", "owner", "attendees", "transcript" ], "additionalProperties": false } }, "required": [ "meeting" ], "additionalProperties": false } }, "required": [ "event", "deliveryId", "timestamp", "webhookId", "data" ], "additionalProperties": false } ``` ## resource.created A published shared resource was created or made shared. Contract version: **v1**. ```json { "type": "object", "properties": { "event_id": { "type": "string", "description": "Stable event identity. Deduplicate on this value, including replays." }, "event": { "type": "string", "const": "resource.created" }, "version": { "type": "string", "const": "v1" }, "occurred_at": { "type": "string", "format": "date-time" }, "resource": { "type": "object", "properties": { "id": { "type": "string" }, "type": { "type": "string" }, "version": { "type": "string", "description": "Opaque resource revision. Events may arrive out of order." } }, "required": [ "id", "type", "version" ], "additionalProperties": false }, "changed_fields": { "type": "array", "items": { "type": "string" }, "description": "Names of externally exposed fields changed by this commit. Never field values." }, "test": { "type": "boolean", "const": true } }, "required": [ "event_id", "event", "version", "occurred_at", "resource" ], "additionalProperties": false } ``` ## resource.updated An externally exposed field on a published shared resource changed. Contract version: **v1**. ```json { "type": "object", "properties": { "event_id": { "type": "string", "description": "Stable event identity. Deduplicate on this value, including replays." }, "event": { "type": "string", "const": "resource.updated" }, "version": { "type": "string", "const": "v1" }, "occurred_at": { "type": "string", "format": "date-time" }, "resource": { "type": "object", "properties": { "id": { "type": "string" }, "type": { "type": "string" }, "version": { "type": "string", "description": "Opaque resource revision. Events may arrive out of order." } }, "required": [ "id", "type", "version" ], "additionalProperties": false }, "changed_fields": { "type": "array", "items": { "type": "string" }, "description": "Names of externally exposed fields changed by this commit. Never field values." }, "test": { "type": "boolean", "const": true } }, "required": [ "event_id", "event", "version", "occurred_at", "resource" ], "additionalProperties": false } ``` ## resource.deleted A published shared resource was deleted or made private. Remove it from your local copy. Contract version: **v1**. ```json { "type": "object", "properties": { "event_id": { "type": "string", "description": "Stable event identity. Deduplicate on this value, including replays." }, "event": { "type": "string", "const": "resource.deleted" }, "version": { "type": "string", "const": "v1" }, "occurred_at": { "type": "string", "format": "date-time" }, "resource": { "type": "object", "properties": { "id": { "type": "string" }, "type": { "type": "string" }, "version": { "type": "string", "description": "Opaque resource revision. Events may arrive out of order." } }, "required": [ "id", "type", "version" ], "additionalProperties": false }, "changed_fields": { "type": "array", "items": { "type": "string" }, "description": "Names of externally exposed fields changed by this commit. Never field values." }, "test": { "type": "boolean", "const": true } }, "required": [ "event_id", "event", "version", "occurred_at", "resource" ], "additionalProperties": false } ``` --- # Get rule Read an automation’s trigger, state and recent run outcomes. Open Brigg to inspect or change its actions. Reading this status does not execute the automation or its record selection. POST https://api.brigg.app/v1/operations/automation.GetRule ## Access & visibility Allow `automation.GetRule` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `rule_id` | string | Yes | Use the returned rule_id together with its app_id. A rule's display label is not its ID. [automation.ListRules](/developers/reference/automation/ListRules). At least 1 character. | | `app_id` | string | No | Use the owning app's app_id from ListApps, or core for workspace-native automations. This is not a public operation namespace. Omit only when the request field is optional. [workspace.ListApps](/developers/reference/workspace/ListApps). | ## Inspect before changing an automation Find a rule with [List rules](/developers/reference/automation/ListRules), then read [Get rule](/developers/reference/automation/GetRule) for its current configuration and recent runs. Preserve the `rule_id` and `app_id` pair. `enabled` controls future trigger handling; it is not a report that an earlier run succeeded. Check `can_manage` before offering an edit or delete action. Built-in locked rules may be visible without being editable. The public update can pause a rule with enabled: false. It cannot resume a rule or author new actions; perform those steps in Brigg. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `rule` | [object](#response-rule) | Yes | Automation configuration and its current execution state. | | `runs` | array of [object](#response-runs) | Yes | Recent execution outcomes; this does not execute the automation. | ### response.rule | Field | Type | Required | Description | | --- | --- | --- | --- | | `rule_id` | string | Yes | Rule identifier. | | `app_id` | string | Yes | App identifier. | | `description` | string or null | No | Descriptive text. | | `trigger` | [object](#response-rule-trigger) | No | Condition or schedule that starts the automation. | | `enabled` | boolean | Yes | Whether this feature is enabled. | | `locked` | boolean | Yes | Built-in: neither disabled nor deleted. | | `scope` | string | Yes | `org` for an org-level rule, `mine` for the caller's own. | | `can_manage` | boolean | Yes | Whether the acting member can manage this automation. | | `created_at` | number | Yes | Creation time in Unix milliseconds. | | `fired_count` | number | Yes | Number of recorded trigger activations. | | `last_fired_at` | number or null | Yes | Most recent trigger activation time, in Unix milliseconds. | | `next_fire_at` | number or null | Yes | Next scheduled activation time, in Unix milliseconds. | | `parked` | boolean | Yes | Whether this automation is currently held from running. | ### response.rule.trigger | Field | Type | Required | Description | | --- | --- | --- | --- | | `type` | string | Yes | Type identifying which variant of this model applies. Allowed: `"on_cron"`, `"on_create"`, `"on_update"`, `"on_delete"`, `"on_message"`. | | `schedule` | string | No | Cron expression for an on_cron trigger, typically minute hour day-of-month month day-of-week. For example, 0 9 * * 1-5 runs at 09:00 on weekdays in timezone. Not present on record-change triggers. | | `timezone` | string | No | IANA time zone, for example Europe/Oslo. | | `resource_type` | string | No | Resource type whose changes can trigger this automation. | | `fields` | array of string | No | Record fields whose changes the trigger observes. | | `transition` | [object](#response-rule-trigger-transition) | No | Field-value transition that qualifies a record change. | | `channel` | string | No | Communication channel to which this trigger applies. | ### response.rule.trigger.transition | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | Record field whose change the trigger observes. | | `to` | string or boolean or number | Yes | Destination value that the field must change to. | ### response.runs[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `run_id` | string | Yes | Run identifier. | | `rule_id` | string | Yes | Rule identifier. | | `app_id` | string | Yes | App identifier. | | `trigger_type` | string | No | Trigger category identifying how the automation starts. | | `status` | string | Yes | `ok` / `partial` / `error` / `skipped` — the roll-up over the rule's actions. | | `fired_at` | number | Yes | Time of this trigger activation, in Unix milliseconds. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 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. | ## Next steps - [List rules](/developers/reference/automation/ListRules) - [Update rule](/developers/reference/automation/UpdateRule) - [List apps](/developers/reference/workspace/ListApps) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/automation.GetRule' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Brigg-Act-As: $BRIGG_ACT_AS" \ --data-raw '{ "rule_id": "e_example" }' ``` #### 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 response = await fetch("https://api.brigg.app/v1/operations/automation.GetRule", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Brigg-Act-As": actAs, }, body: JSON.stringify({ "rule_id": "e_example" }), }); 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 payload = { "rule_id": "e_example" } request = Request( "https://api.brigg.app/v1/operations/automation.GetRule", 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"], }, 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 { "rule": { "rule_id": "e_example", "app_id": "e_example", "enabled": true, "locked": false, "scope": "org", "can_manage": false, "created_at": 1794301200000, "fired_count": 1, "last_fired_at": null, "next_fire_at": null, "parked": false }, "runs": [] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "rule_id": { "type": "string", "minLength": 1, "description": "Use the returned rule_id together with its app_id. A rule's display label is not its ID. [automation.ListRules](/developers/reference/automation/ListRules)." }, "app_id": { "type": "string", "description": "Use the owning app's app_id from ListApps, or core for workspace-native automations. This is not a public operation namespace. Omit only when the request field is optional. [workspace.ListApps](/developers/reference/workspace/ListApps)." } }, "required": [ "rule_id" ], "additionalProperties": false, "examples": [ { "rule_id": "e_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "rule": { "type": "object", "properties": { "rule_id": { "type": "string", "description": "Rule identifier." }, "app_id": { "type": "string", "description": "App identifier." }, "description": { "type": [ "string", "null" ], "description": "Descriptive text." }, "trigger": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "on_cron", "on_create", "on_update", "on_delete", "on_message" ], "description": "Type identifying which variant of this model applies." }, "schedule": { "type": "string", "description": "Cron expression for an on_cron trigger, typically minute hour day-of-month month day-of-week. For example, 0 9 * * 1-5 runs at 09:00 on weekdays in timezone. Not present on record-change triggers." }, "timezone": { "type": "string", "description": "IANA time zone, for example Europe/Oslo." }, "resource_type": { "type": "string", "description": "Resource type whose changes can trigger this automation." }, "fields": { "type": "array", "items": { "type": "string" }, "description": "Record fields whose changes the trigger observes." }, "transition": { "type": "object", "properties": { "field": { "type": "string", "description": "Record field whose change the trigger observes." }, "to": { "type": [ "string", "boolean", "number" ], "description": "Destination value that the field must change to." } }, "required": [ "field", "to" ], "additionalProperties": false, "description": "Field-value transition that qualifies a record change." }, "channel": { "type": "string", "description": "Communication channel to which this trigger applies." } }, "required": [ "type" ], "additionalProperties": false, "description": "Condition or schedule that starts the automation." }, "enabled": { "type": "boolean", "description": "Whether this feature is enabled." }, "locked": { "type": "boolean", "description": "Built-in: neither disabled nor deleted." }, "scope": { "type": "string", "description": "`org` for an org-level rule, `mine` for the caller's own." }, "can_manage": { "type": "boolean", "description": "Whether the acting member can manage this automation." }, "created_at": { "type": "number", "description": "Creation time in Unix milliseconds." }, "fired_count": { "type": "number", "description": "Number of recorded trigger activations." }, "last_fired_at": { "type": [ "number", "null" ], "description": "Most recent trigger activation time, in Unix milliseconds." }, "next_fire_at": { "type": [ "number", "null" ], "description": "Next scheduled activation time, in Unix milliseconds." }, "parked": { "type": "boolean", "description": "Whether this automation is currently held from running." } }, "required": [ "rule_id", "app_id", "enabled", "locked", "scope", "can_manage", "created_at", "fired_count", "last_fired_at", "next_fire_at", "parked" ], "additionalProperties": false, "description": "Automation configuration and its current execution state." }, "runs": { "type": "array", "items": { "type": "object", "properties": { "run_id": { "type": "string", "description": "Run identifier." }, "rule_id": { "type": "string", "description": "Rule identifier." }, "app_id": { "type": "string", "description": "App identifier." }, "trigger_type": { "type": "string", "description": "Trigger category identifying how the automation starts." }, "status": { "type": "string", "description": "`ok` / `partial` / `error` / `skipped` — the roll-up over the rule's actions." }, "fired_at": { "type": "number", "description": "Time of this trigger activation, in Unix milliseconds." } }, "required": [ "run_id", "rule_id", "app_id", "status", "fired_at" ], "additionalProperties": false }, "description": "Recent execution outcomes; this does not execute the automation." } }, "required": [ "rule", "runs" ], "additionalProperties": false, "examples": [ { "rule": { "rule_id": "e_example", "app_id": "e_example", "enabled": true, "locked": false, "scope": "org", "can_manage": false, "created_at": 1794301200000, "fired_count": 1, "last_fired_at": null, "next_fire_at": null, "parked": false }, "runs": [] } ] } ``` --- # List rules List workspace automations and your own personal automations, with the status of their latest runs. Execution definitions stay in Brigg; this view contains no SQL, action payloads or generated run contents. POST https://api.brigg.app/v1/operations/automation.ListRules ## Access & visibility Allow `automation.ListRules` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `app_id` | string | No | Use the owning app's app_id from ListApps, or core for workspace-native automations. This is not a public operation namespace. Omit only when the request field is optional. [workspace.ListApps](/developers/reference/workspace/ListApps). | | `limit` | integer | No | Maximum number of visible rules to return, newest-created first. Defaults to 50; this operation has no continuation cursor. Use app_id to narrow the catalogue. Maximum: 50. Greater than 0. | ## Inspect before changing an automation Find a rule with [List rules](/developers/reference/automation/ListRules), then read [Get rule](/developers/reference/automation/GetRule) for its current configuration and recent runs. Preserve the `rule_id` and `app_id` pair. `enabled` controls future trigger handling; it is not a report that an earlier run succeeded. Check `can_manage` before offering an edit or delete action. Built-in locked rules may be visible without being editable. The public update can pause a rule with enabled: false. It cannot resume a rule or author new actions; perform those steps in Brigg. ## Response Returns **200 OK** with a JSON body. This operation has no continuation cursor. An empty `items` array means no matching visible results were returned. This is a bounded operational view, not a full export or change feed. If the result reaches limit, additional matching rules may exist. Use an app filter for a narrower view; do not invent a cursor or offset. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [Automation rule](#automation-rule-response-items) | Yes | Rules visible to the acting member, optionally restricted to app_id and bounded by limit. This operation has no cursor pagination. | ### Automation rule · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `rule_id` | string | Yes | Rule ID returned by the rule catalogue; use it with GetRule or UpdateRule. | | `app_id` | string | Yes | App that owns the rule. This is an app ID, not a public operation namespace. | | `description` | string or null | No | Descriptive text. | | `trigger` | [object](#response-items-trigger) | No | Event or schedule that starts this rule; the fields depend on type. | | `enabled` | boolean | Yes | Whether new matching events can start this rule. It does not report the outcome of past runs. | | `locked` | boolean | Yes | Built-in: neither disabled nor deleted. | | `scope` | string | Yes | `org` for an org-level rule, `mine` for the caller's own. | | `can_manage` | boolean | Yes | Whether the acting member can manage this rule. Locked built-in rules cannot be disabled or deleted. | | `created_at` | number | Yes | Creation time in Unix milliseconds. | | `last_run` | [object](#response-items-last-run) or null | Yes | Most recent execution summary, or null if the rule has never run. | ### response.items[].trigger | Field | Type | Required | Description | | --- | --- | --- | --- | | `type` | string | Yes | Type identifying which variant of this model applies. Allowed: `"on_cron"`, `"on_create"`, `"on_update"`, `"on_delete"`, `"on_message"`. | | `schedule` | string | No | Cron expression for an on_cron trigger, typically minute hour day-of-month month day-of-week. For example, 0 9 * * 1-5 runs at 09:00 on weekdays in timezone. Not present on record-change triggers. | | `timezone` | string | No | IANA time zone, for example Europe/Oslo. | | `resource_type` | string | No | Resource type whose changes can trigger this automation. | | `fields` | array of string | No | Record fields whose changes the trigger observes. | | `transition` | [object](#response-items-trigger-transition) | No | Field-value transition that qualifies a record change. | | `channel` | string | No | Communication channel to which this trigger applies. | ### response.items[].trigger.transition | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | Record field whose change the trigger observes. | | `to` | string or boolean or number | Yes | Destination value that the field must change to. | ### response.items[].last_run | Field | Type | Required | Description | | --- | --- | --- | --- | | `run_id` | string | No | Run identifier. | | `rule_id` | string | No | Rule identifier. | | `app_id` | string | No | App identifier. | | `trigger_type` | string | No | Trigger category identifying how the automation starts. | | `status` | string | No | `ok` / `partial` / `error` / `skipped` — the roll-up over the rule's actions. | | `fired_at` | number | No | Time of this trigger activation, in Unix milliseconds. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 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. | ## Next steps - [Get rule](/developers/reference/automation/GetRule) - [Update rule](/developers/reference/automation/UpdateRule) - [List apps](/developers/reference/workspace/ListApps) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Recent rule outcomes A failed last run does not disable a rule automatically. Read GetRule with this rule_id/app_id pair for recent execution summaries. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/automation.ListRules' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Brigg-Act-As: $BRIGG_ACT_AS" \ --data-raw '{ "app_id": "core", "limit": 20 }' ``` #### 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 response = await fetch("https://api.brigg.app/v1/operations/automation.ListRules", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Brigg-Act-As": actAs, }, body: JSON.stringify({ "app_id": "core", "limit": 20 }), }); 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 payload = { "app_id": "core", "limit": 20 } request = Request( "https://api.brigg.app/v1/operations/automation.ListRules", 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"], }, 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 { "items": [ { "rule_id": "rule_follow_up", "app_id": "core", "description": "Create a follow-up task when a deal changes stage.", "trigger": { "type": "on_update", "resource_type": "core:Deal", "fields": [ "stage" ] }, "enabled": true, "locked": false, "scope": "org", "can_manage": true, "created_at": 1794301200000, "last_run": { "run_id": "run_follow_up_1", "rule_id": "rule_follow_up", "app_id": "core", "trigger_type": "on_update", "status": "error", "fired_at": 1794387600000 } } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "app_id": { "type": "string", "description": "Use the owning app's app_id from ListApps, or core for workspace-native automations. This is not a public operation namespace. Omit only when the request field is optional. [workspace.ListApps](/developers/reference/workspace/ListApps)." }, "limit": { "type": "integer", "exclusiveMinimum": 0, "maximum": 50, "description": "Maximum number of visible rules to return, newest-created first. Defaults to 50; this operation has no continuation cursor. Use app_id to narrow the catalogue." } }, "additionalProperties": false, "examples": [ { "app_id": "core", "limit": 20 } ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "rule_id": { "type": "string", "description": "Rule ID returned by the rule catalogue; use it with GetRule or UpdateRule.", "examples": [ "rule_follow_up" ] }, "app_id": { "type": "string", "description": "App that owns the rule. This is an app ID, not a public operation namespace.", "examples": [ "core" ] }, "description": { "type": [ "string", "null" ], "description": "Descriptive text.", "examples": [ "Create a follow-up task when a deal changes stage." ] }, "trigger": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "on_cron", "on_create", "on_update", "on_delete", "on_message" ], "description": "Type identifying which variant of this model applies." }, "schedule": { "type": "string", "description": "Cron expression for an on_cron trigger, typically minute hour day-of-month month day-of-week. For example, 0 9 * * 1-5 runs at 09:00 on weekdays in timezone. Not present on record-change triggers." }, "timezone": { "type": "string", "description": "IANA time zone, for example Europe/Oslo." }, "resource_type": { "type": "string", "description": "Resource type whose changes can trigger this automation." }, "fields": { "type": "array", "items": { "type": "string" }, "description": "Record fields whose changes the trigger observes." }, "transition": { "type": "object", "properties": { "field": { "type": "string", "description": "Record field whose change the trigger observes." }, "to": { "type": [ "string", "boolean", "number" ], "description": "Destination value that the field must change to." } }, "required": [ "field", "to" ], "additionalProperties": false, "description": "Field-value transition that qualifies a record change." }, "channel": { "type": "string", "description": "Communication channel to which this trigger applies." } }, "required": [ "type" ], "additionalProperties": false, "description": "Event or schedule that starts this rule; the fields depend on type.", "examples": [ { "type": "on_update", "resource_type": "core:Deal", "fields": [ "stage" ] } ] }, "enabled": { "type": "boolean", "description": "Whether new matching events can start this rule. It does not report the outcome of past runs.", "examples": [ true ] }, "locked": { "type": "boolean", "description": "Built-in: neither disabled nor deleted.", "examples": [ false ] }, "scope": { "type": "string", "description": "`org` for an org-level rule, `mine` for the caller's own.", "examples": [ "org" ] }, "can_manage": { "type": "boolean", "description": "Whether the acting member can manage this rule. Locked built-in rules cannot be disabled or deleted.", "examples": [ true ] }, "created_at": { "type": "number", "description": "Creation time in Unix milliseconds." }, "last_run": { "type": [ "object", "null" ], "properties": { "run_id": { "type": "string", "description": "Run identifier." }, "rule_id": { "type": "string", "description": "Rule identifier." }, "app_id": { "type": "string", "description": "App identifier." }, "trigger_type": { "type": "string", "description": "Trigger category identifying how the automation starts." }, "status": { "type": "string", "description": "`ok` / `partial` / `error` / `skipped` — the roll-up over the rule's actions." }, "fired_at": { "type": "number", "description": "Time of this trigger activation, in Unix milliseconds." } }, "additionalProperties": false, "description": "Most recent execution summary, or null if the rule has never run.", "examples": [ null ] } }, "required": [ "rule_id", "app_id", "enabled", "locked", "scope", "can_manage", "created_at", "last_run" ], "additionalProperties": false, "title": "Automation rule" }, "description": "Rules visible to the acting member, optionally restricted to app_id and bounded by limit. This operation has no cursor pagination." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "rule_id": "rule_follow_up", "app_id": "core", "description": "Create a follow-up task when a deal changes stage.", "trigger": { "type": "on_update", "resource_type": "core:Deal", "fields": [ "stage" ] }, "enabled": true, "locked": false, "scope": "org", "can_manage": true, "created_at": 1794301200000, "last_run": { "run_id": "run_follow_up_1", "rule_id": "rule_follow_up", "app_id": "core", "trigger_type": "on_update", "status": "error", "fired_at": 1794387600000 } } ] } ] } ``` --- # Delete rule Delete an automation you manage. Built-in automations cannot be deleted. Deleting a rule prevents future runs; it does not undo work already performed. POST https://api.brigg.app/v1/operations/automation.DeleteRule ## Access & visibility Allow `automation.DeleteRule` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `rule_id` | string | Yes | Use the returned rule_id together with its app_id. A rule's display label is not its ID. [automation.ListRules](/developers/reference/automation/ListRules). At least 1 character. | | `app_id` | string | No | Use the owning app's app_id from ListApps, or core for workspace-native automations. This is not a public operation namespace. Omit only when the request field is optional. [workspace.ListApps](/developers/reference/workspace/ListApps). | ## Inspect before changing an automation Find a rule with [List rules](/developers/reference/automation/ListRules), then read [Get rule](/developers/reference/automation/GetRule) for its current configuration and recent runs. Preserve the `rule_id` and `app_id` pair. `enabled` controls future trigger handling; it is not a report that an earlier run succeeded. Check `can_manage` before offering an edit or delete action. Built-in locked rules may be visible without being editable. The public update can pause a rule with enabled: false. It cannot resume a rule or author new actions; perform those steps in Brigg. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `rule_id` | string | Yes | Rule identifier. | | `app_id` | string | Yes | App identifier. | | `deleted` | boolean | Yes | deleted when this request removed the record; already_deleted when it was already absent. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | ## Next steps - [List rules](/developers/reference/automation/ListRules) - [Get rule](/developers/reference/automation/GetRule) - [Update rule](/developers/reference/automation/UpdateRule) - [List apps](/developers/reference/workspace/ListApps) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/automation.DeleteRule' \ -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 '{ "rule_id": "e_example" }' ``` #### 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/automation.DeleteRule", { 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({ "rule_id": "e_example" }), }); 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 = { "rule_id": "e_example" } request = Request( "https://api.brigg.app/v1/operations/automation.DeleteRule", 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 { "rule_id": "e_example", "app_id": "e_example", "deleted": false } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "rule_id": { "type": "string", "minLength": 1, "description": "Use the returned rule_id together with its app_id. A rule's display label is not its ID. [automation.ListRules](/developers/reference/automation/ListRules)." }, "app_id": { "type": "string", "description": "Use the owning app's app_id from ListApps, or core for workspace-native automations. This is not a public operation namespace. Omit only when the request field is optional. [workspace.ListApps](/developers/reference/workspace/ListApps)." } }, "required": [ "rule_id" ], "additionalProperties": false, "examples": [ { "rule_id": "e_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "rule_id": { "type": "string", "description": "Rule identifier." }, "app_id": { "type": "string", "description": "App identifier." }, "deleted": { "type": "boolean", "description": "deleted when this request removed the record; already_deleted when it was already absent." } }, "required": [ "rule_id", "app_id", "deleted" ], "additionalProperties": false, "examples": [ { "rule_id": "e_example", "app_id": "e_example", "deleted": false } ] } ``` --- # Update rule Pause an automation you manage. To create, resume or test an automation, use Brigg: it runs with its owner’s permissions after the current API call has ended. POST https://api.brigg.app/v1/operations/automation.UpdateRule ## Access & visibility Allow `automation.UpdateRule` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `rule_id` | string | Yes | Use the returned rule_id together with its app_id. A rule's display label is not its ID. [automation.ListRules](/developers/reference/automation/ListRules). At least 1 character. | | `app_id` | string | No | Use the owning app's app_id from ListApps, or core for workspace-native automations. This is not a public operation namespace. Omit only when the request field is optional. [workspace.ListApps](/developers/reference/workspace/ListApps). | | `enabled` | boolean | Yes | Pause an automation. Creation, resumption and test execution require a person in Brigg because a rule runs later with its owner's permissions. Always `false`. | ## Inspect before changing an automation Find a rule with [List rules](/developers/reference/automation/ListRules), then read [Get rule](/developers/reference/automation/GetRule) for its current configuration and recent runs. Preserve the `rule_id` and `app_id` pair. `enabled` controls future trigger handling; it is not a report that an earlier run succeeded. Check `can_manage` before offering an edit or delete action. Built-in locked rules may be visible without being editable. The public update can pause a rule with enabled: false. It cannot resume a rule or author new actions; perform those steps in Brigg. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `rule_id` | string | Yes | Rule identifier. | | `app_id` | string | Yes | App identifier. | | `rule` | [object](#response-rule) or null | Yes | The definition AS STORED. | | `enabled` | boolean | Yes | Whether this feature is enabled. | ### response.rule | Field | Type | Required | Description | | --- | --- | --- | --- | | `rule_id` | string | Yes | Rule identifier. | | `app_id` | string | Yes | App identifier. | | `description` | string or null | No | Descriptive text. | | `trigger` | [object](#response-rule-trigger) | No | Condition or schedule that starts the automation. | | `enabled` | boolean | Yes | Whether this feature is enabled. | | `locked` | boolean | Yes | Built-in: neither disabled nor deleted. | | `scope` | string | Yes | `org` for an org-level rule, `mine` for the caller's own. | | `can_manage` | boolean | Yes | Whether the acting member can manage this automation. | | `created_at` | number | Yes | Creation time in Unix milliseconds. | ### response.rule.trigger | Field | Type | Required | Description | | --- | --- | --- | --- | | `type` | string | Yes | Type identifying which variant of this model applies. Allowed: `"on_cron"`, `"on_create"`, `"on_update"`, `"on_delete"`, `"on_message"`. | | `schedule` | string | No | Cron expression for an on_cron trigger, typically minute hour day-of-month month day-of-week. For example, 0 9 * * 1-5 runs at 09:00 on weekdays in timezone. Not present on record-change triggers. | | `timezone` | string | No | IANA time zone, for example Europe/Oslo. | | `resource_type` | string | No | Resource type whose changes can trigger this automation. | | `fields` | array of string | No | Record fields whose changes the trigger observes. | | `transition` | [object](#response-rule-trigger-transition) | No | Field-value transition that qualifies a record change. | | `channel` | string | No | Communication channel to which this trigger applies. | ### response.rule.trigger.transition | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | Record field whose change the trigger observes. | | `to` | string or boolean or number | Yes | Destination value that the field must change to. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | ## Next steps - [List rules](/developers/reference/automation/ListRules) - [Get rule](/developers/reference/automation/GetRule) - [List apps](/developers/reference/workspace/ListApps) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/automation.UpdateRule' \ -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 '{ "rule_id": "e_example", "enabled": false }' ``` #### 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/automation.UpdateRule", { 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({ "rule_id": "e_example", "enabled": false }), }); 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 = { "rule_id": "e_example", "enabled": False } request = Request( "https://api.brigg.app/v1/operations/automation.UpdateRule", 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 { "rule_id": "e_example", "app_id": "e_example", "rule": null, "enabled": true } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "rule_id": { "type": "string", "minLength": 1, "description": "Use the returned rule_id together with its app_id. A rule's display label is not its ID. [automation.ListRules](/developers/reference/automation/ListRules)." }, "app_id": { "type": "string", "description": "Use the owning app's app_id from ListApps, or core for workspace-native automations. This is not a public operation namespace. Omit only when the request field is optional. [workspace.ListApps](/developers/reference/workspace/ListApps)." }, "enabled": { "type": "boolean", "const": false, "description": "Pause an automation. Creation, resumption and test execution require a person in Brigg because a rule runs later with its owner's permissions." } }, "required": [ "rule_id", "enabled" ], "additionalProperties": false, "examples": [ { "rule_id": "e_example", "enabled": false } ] } ``` ```json-schema-response { "type": "object", "properties": { "rule_id": { "type": "string", "description": "Rule identifier." }, "app_id": { "type": "string", "description": "App identifier." }, "rule": { "type": [ "object", "null" ], "properties": { "rule_id": { "type": "string", "description": "Rule identifier." }, "app_id": { "type": "string", "description": "App identifier." }, "description": { "type": [ "string", "null" ], "description": "Descriptive text." }, "trigger": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "on_cron", "on_create", "on_update", "on_delete", "on_message" ], "description": "Type identifying which variant of this model applies." }, "schedule": { "type": "string", "description": "Cron expression for an on_cron trigger, typically minute hour day-of-month month day-of-week. For example, 0 9 * * 1-5 runs at 09:00 on weekdays in timezone. Not present on record-change triggers." }, "timezone": { "type": "string", "description": "IANA time zone, for example Europe/Oslo." }, "resource_type": { "type": "string", "description": "Resource type whose changes can trigger this automation." }, "fields": { "type": "array", "items": { "type": "string" }, "description": "Record fields whose changes the trigger observes." }, "transition": { "type": "object", "properties": { "field": { "type": "string", "description": "Record field whose change the trigger observes." }, "to": { "type": [ "string", "boolean", "number" ], "description": "Destination value that the field must change to." } }, "required": [ "field", "to" ], "additionalProperties": false, "description": "Field-value transition that qualifies a record change." }, "channel": { "type": "string", "description": "Communication channel to which this trigger applies." } }, "required": [ "type" ], "additionalProperties": false, "description": "Condition or schedule that starts the automation." }, "enabled": { "type": "boolean", "description": "Whether this feature is enabled." }, "locked": { "type": "boolean", "description": "Built-in: neither disabled nor deleted." }, "scope": { "type": "string", "description": "`org` for an org-level rule, `mine` for the caller's own." }, "can_manage": { "type": "boolean", "description": "Whether the acting member can manage this automation." }, "created_at": { "type": "number", "description": "Creation time in Unix milliseconds." } }, "required": [ "rule_id", "app_id", "enabled", "locked", "scope", "can_manage", "created_at" ], "description": "The definition AS STORED.", "additionalProperties": false }, "enabled": { "type": "boolean", "description": "Whether this feature is enabled." } }, "required": [ "rule_id", "app_id", "rule", "enabled" ], "additionalProperties": false, "examples": [ { "rule_id": "e_example", "app_id": "e_example", "rule": null, "enabled": true } ] } ``` --- # Get billing Read the workspace's plan, credit balance and available billing actions. POST https://api.brigg.app/v1/operations/billing.GetBilling ## Access & visibility Allow `billing.GetBilling` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/permissions) ## Request No parameters. Send an empty JSON object (`{}`). ## Balance, charges and underlying usage [Get billing](/developers/reference/billing/GetBilling) returns the current workspace balance. [List credit ledger](/developers/reference/billing/ListCreditLedger) returns recent balance movements, newest first: a negative amount deducts credit; a positive amount adds it. The default is 50 rows and the maximum is 500, with no cursor for older pages. For spending over a period, use [List usage](/developers/reference/billing/ListUsage). Its from and to values are inclusive Unix millisecond timestamps. Use totals.spent_nok for charged credit: it comes from the credit ledger. The items describe individual credit charges and their activities. Use totals for period spending: item detail can be incomplete. Credit figures are in Norwegian kroner, not minor currency units. Some plans hide credit information. An authorized member can still receive credit_info_hidden on those plans; changing the key's grants does not expose it. Storage usage is a separate byte quota, not a currency balance. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `billing` | [Billing](#billing-response-billing) | Yes | Current plan, payment availability and credit balance. | | `online_payments_available` | boolean | Yes | Whether this workspace can use Brigg's online payment flow. | ### Billing · response.billing | Field | Type | Required | Description | | --- | --- | --- | --- | | `plan` | string | Yes | Current workspace subscription plan. Allowed: `"trial"`, `"free"`, `"start"`, `"team"`, `"enterprise"`, `"legacy"`, `"invoiced"`. | | `balance_nok` | number | Yes | Available credit in Norwegian kroner, not øre. | | `monthly_credit_nok` | number | Yes | Credit included each month, in Norwegian kroner. | | `last_refill_at` | null or number | Yes | Time credits were most recently refilled, in Unix milliseconds. | | `next_refill_at` | null or number | Yes | Next scheduled credit refill, in Unix milliseconds. | | `trial_ends_at` | null or number | Yes | Trial expiry time, in Unix milliseconds. | | `has_payment_method` | boolean | Yes | Whether a payment method is configured for the workspace. Allowed: `false`, `true`. | | `created_at` | number | Yes | Creation time in Unix milliseconds. | | `updated_at` | number | Yes | Last update time in Unix milliseconds. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | | 403 | `credit_info_hidden` | This workspace plan does not expose credit and usage details. | ## Next steps - [List usage](/developers/reference/billing/ListUsage) - [List credit ledger](/developers/reference/billing/ListCreditLedger) - [Get storage usage](/developers/reference/billing/GetStorageUsage) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/billing.GetBilling' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{}' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/billing.GetBilling", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/billing.GetBilling", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "billing": { "plan": "team", "balance_nok": 487.5, "monthly_credit_nok": 500, "last_refill_at": null, "next_refill_at": null, "trial_ends_at": null, "has_payment_method": false, "created_at": 1794301200000, "updated_at": 1794301200000 }, "online_payments_available": false } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": {}, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "billing": { "description": "Current plan, payment availability and credit balance.", "title": "Billing", "type": "object", "properties": { "plan": { "type": "string", "enum": [ "trial", "free", "start", "team", "enterprise", "legacy", "invoiced" ], "description": "Current workspace subscription plan." }, "balance_nok": { "type": "number", "description": "Available credit in Norwegian kroner, not øre." }, "monthly_credit_nok": { "type": "number", "description": "Credit included each month, in Norwegian kroner." }, "last_refill_at": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Time credits were most recently refilled, in Unix milliseconds." }, "next_refill_at": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Next scheduled credit refill, in Unix milliseconds." }, "trial_ends_at": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Trial expiry time, in Unix milliseconds." }, "has_payment_method": { "type": "boolean", "enum": [ false, true ], "description": "Whether a payment method is configured for the workspace." }, "created_at": { "type": "number", "description": "Creation time in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Last update time in Unix milliseconds." } }, "required": [ "plan", "balance_nok", "monthly_credit_nok", "last_refill_at", "next_refill_at", "trial_ends_at", "has_payment_method", "created_at", "updated_at" ], "additionalProperties": false }, "online_payments_available": { "type": "boolean", "description": "Whether this workspace can use Brigg's online payment flow." } }, "required": [ "billing", "online_payments_available" ], "additionalProperties": false, "examples": [ { "billing": { "plan": "team", "balance_nok": 487.5, "monthly_credit_nok": 500, "last_refill_at": null, "next_refill_at": null, "trial_ends_at": null, "has_payment_method": false, "created_at": 1794301200000, "updated_at": 1794301200000 }, "online_payments_available": false } ] } ``` --- # Get storage usage Read workspace storage usage in bytes, with shared, per-member and total usage against the plan allowance. POST https://api.brigg.app/v1/operations/billing.GetStorageUsage ## Access & visibility Allow `billing.GetStorageUsage` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/permissions) ## Request No parameters. Send an empty JSON object (`{}`). ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `plan` | string | Yes | Current workspace subscription plan. | | `quota_bytes` | number | Yes | Storage allowance for the workspace, in bytes. | | `used_bytes` | number | Yes | Total storage currently used, in bytes. | | `shared_bytes` | number | Yes | Storage used by workspace-shared content, in bytes. | | `user_bytes` | number | Yes | Storage used by personal content, in bytes. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/billing.GetStorageUsage' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{}' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/billing.GetStorageUsage", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/billing.GetStorageUsage", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "plan": "team", "quota_bytes": 10737418240, "used_bytes": 1610612736, "shared_bytes": 1073741824, "user_bytes": 536870912 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": {}, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "plan": { "type": "string", "description": "Current workspace subscription plan." }, "quota_bytes": { "type": "number", "description": "Storage allowance for the workspace, in bytes." }, "used_bytes": { "type": "number", "description": "Total storage currently used, in bytes." }, "shared_bytes": { "type": "number", "description": "Storage used by workspace-shared content, in bytes." }, "user_bytes": { "type": "number", "description": "Storage used by personal content, in bytes." } }, "required": [ "plan", "quota_bytes", "used_bytes", "shared_bytes", "user_bytes" ], "additionalProperties": false, "examples": [ { "plan": "team", "quota_bytes": 10737418240, "used_bytes": 1610612736, "shared_bytes": 1073741824, "user_bytes": 536870912 } ] } ``` --- # List credit ledger List credit additions, deductions and running balances, newest first. POST https://api.brigg.app/v1/operations/billing.ListCreditLedger ## Access & visibility Allow `billing.ListCreditLedger` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `limit` | integer | No | Maximum number of matching results to return. This operation does not provide a continuation cursor. Range: 1 to 500. | ## Balance, charges and underlying usage [Get billing](/developers/reference/billing/GetBilling) returns the current workspace balance. [List credit ledger](/developers/reference/billing/ListCreditLedger) returns recent balance movements, newest first: a negative amount deducts credit; a positive amount adds it. The default is 50 rows and the maximum is 500, with no cursor for older pages. For spending over a period, use [List usage](/developers/reference/billing/ListUsage). Its from and to values are inclusive Unix millisecond timestamps. Use totals.spent_nok for charged credit: it comes from the credit ledger. The items describe individual credit charges and their activities. Use totals for period spending: item detail can be incomplete. Credit figures are in Norwegian kroner, not minor currency units. Some plans hide credit information. An authorized member can still receive credit_info_hidden on those plans; changing the key's grants does not expose it. Storage usage is a separate byte quota, not a currency balance. ## Response Returns **200 OK** with a JSON body. This operation has no continuation cursor. An empty `items` array means no matching visible results were returned. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [Credit ledger entry](#credit-ledger-entry-response-items) | Yes | Workspace credit transactions, bounded by limit. This operation has no cursor pagination. | ### Credit ledger entry · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Unique identifier. Use the value returned by a create or list operation. | | `org_id` | string | Yes | Org identifier. | | `kind` | string | Yes | Reason for the credit movement, such as a credit purchase, allowance or usage charge. Allowed: `"trial_grant"`, `"bonus_grant"`, `"monthly_refill"`, `"manual_grant"`, `"topup"`, `"usage"`, `"refund"`, `"adjustment"`. | | `amount_nok` | number | Yes | Credit movement in Norwegian kroner; positive adds credit and negative spends it. | | `balance_after_nok` | number | Yes | Credit balance immediately after this entry, in Norwegian kroner. | | `ref_table` | null or string | Yes | Category of the related billing record. Interpret together with ref_id; it is not an API endpoint. | | `ref_id` | null or string | Yes | Identifier of the related billing record, when a related record was recorded. | | `actor_account_id` | null or string | Yes | Member account responsible for the movement, or null for movements without a member actor. | | `activity` | null or string | Yes | Usage activity associated with the movement, when recorded. | | `note` | null or string | Yes | Additional explanation recorded with the movement, or null when none was supplied. | | `timestamp` | number | Yes | Time this movement was recorded, in Unix milliseconds. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | | 403 | `credit_info_hidden` | This workspace plan does not expose credit and usage details. | ## Next steps - [Get billing](/developers/reference/billing/GetBilling) - [List usage](/developers/reference/billing/ListUsage) - [Get storage usage](/developers/reference/billing/GetStorageUsage) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/billing.ListCreditLedger' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{}' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/billing.ListCreditLedger", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/billing.ListCreditLedger", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "credit_123", "org_id": "org_example", "kind": "usage", "amount_nok": -12.5, "balance_after_nok": 487.5, "ref_table": null, "ref_id": null, "actor_account_id": "account_alex", "activity": null, "note": "Document generation", "timestamp": 1794301200000 } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "limit": { "type": "integer", "minimum": 1, "maximum": 500, "description": "Maximum number of matching results to return. This operation does not provide a continuation cursor." } }, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "title": "Credit ledger entry", "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier. Use the value returned by a create or list operation.", "examples": [ "credit_123" ] }, "org_id": { "type": "string", "description": "Org identifier.", "examples": [ "org_example" ] }, "kind": { "type": "string", "enum": [ "trial_grant", "bonus_grant", "monthly_refill", "manual_grant", "topup", "usage", "refund", "adjustment" ], "description": "Reason for the credit movement, such as a credit purchase, allowance or usage charge.", "examples": [ "usage" ] }, "amount_nok": { "type": "number", "description": "Credit movement in Norwegian kroner; positive adds credit and negative spends it.", "examples": [ -12.5 ] }, "balance_after_nok": { "type": "number", "description": "Credit balance immediately after this entry, in Norwegian kroner.", "examples": [ 487.5 ] }, "ref_table": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Category of the related billing record. Interpret together with ref_id; it is not an API endpoint.", "examples": [ null ] }, "ref_id": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Identifier of the related billing record, when a related record was recorded.", "examples": [ null ] }, "actor_account_id": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Member account responsible for the movement, or null for movements without a member actor.", "examples": [ "account_alex" ] }, "activity": { "anyOf": [ { "type": "null" }, { "type": "string", "const": "chat" }, { "type": "string", "const": "app_build" }, { "type": "string", "const": "app_review" }, { "type": "string", "const": "app_translation" }, { "type": "string", "const": "document_create" }, { "type": "string", "const": "document_fill" }, { "type": "string", "const": "document_index" }, { "type": "string", "const": "document_search" }, { "type": "string", "const": "meeting_transcription" }, { "type": "string", "const": "meeting_summary" }, { "type": "string", "const": "meeting_prep" }, { "type": "string", "const": "meeting_advice" }, { "type": "string", "const": "brief_generate" }, { "type": "string", "const": "brief_action" }, { "type": "string", "const": "contact_enrichment" }, { "type": "string", "const": "company_lookup" }, { "type": "string", "const": "web_search" }, { "type": "string", "const": "web_extract" }, { "type": "string", "const": "image_analysis" }, { "type": "string", "const": "design_generation" }, { "type": "string", "const": "recruiting" }, { "type": "string", "const": "reference_check" }, { "type": "string", "const": "prospects" }, { "type": "string", "const": "voice_call" }, { "type": "string", "const": "phone_number" }, { "type": "string", "const": "outreach_mailbox" }, { "type": "string", "const": "domain_registration" }, { "type": "string", "const": "domain_renewal" }, { "type": "string", "const": "bankid_signature" }, { "type": "string", "const": "sms" }, { "type": "string", "const": "email_draft" }, { "type": "string", "const": "email_validation" }, { "type": "string", "const": "memory_update" }, { "type": "string", "const": "derived_field" }, { "type": "string", "const": "contact_import" }, { "type": "string", "const": "onboarding" }, { "type": "string", "const": "advertising" }, { "type": "string", "const": "browser_agent" }, { "type": "string", "const": "app_operation" } ], "description": "Usage activity associated with the movement, when recorded.", "examples": [ null ] }, "note": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Additional explanation recorded with the movement, or null when none was supplied.", "examples": [ "Document generation" ] }, "timestamp": { "type": "number", "description": "Time this movement was recorded, in Unix milliseconds.", "examples": [ 1794301200000 ] } }, "required": [ "id", "org_id", "kind", "amount_nok", "balance_after_nok", "ref_table", "ref_id", "actor_account_id", "activity", "note", "timestamp" ], "additionalProperties": false }, "description": "Workspace credit transactions, bounded by limit. This operation has no cursor pagination." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "id": "credit_123", "org_id": "org_example", "kind": "usage", "amount_nok": -12.5, "balance_after_nok": 487.5, "ref_table": null, "ref_id": null, "actor_account_id": "account_alex", "activity": null, "note": "Document generation", "timestamp": 1794301200000 } ] } ] } ``` --- # List usage List workspace credit charges and total spending for a time period, in Norwegian kroner. POST https://api.brigg.app/v1/operations/billing.ListUsage ## Access & visibility Allow `billing.ListUsage` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `from` | integer | No | Epoch ms, inclusive. | | `to` | integer | No | Epoch ms, inclusive. | ## Balance, charges and underlying usage [Get billing](/developers/reference/billing/GetBilling) returns the current workspace balance. [List credit ledger](/developers/reference/billing/ListCreditLedger) returns recent balance movements, newest first: a negative amount deducts credit; a positive amount adds it. The default is 50 rows and the maximum is 500, with no cursor for older pages. For spending over a period, use [List usage](/developers/reference/billing/ListUsage). Its from and to values are inclusive Unix millisecond timestamps. Use totals.spent_nok for charged credit: it comes from the credit ledger. The items describe individual credit charges and their activities. Use totals for period spending: item detail can be incomplete. Credit figures are in Norwegian kroner, not minor currency units. Some plans hide credit information. An authorized member can still receive credit_info_hidden on those plans; changing the key's grants does not expose it. Storage usage is a separate byte quota, not a currency balance. ## Response Returns **200 OK** with a JSON body. This operation has no continuation cursor. An empty `items` array means no matching visible results were returned. | Field | Type | Required | Description | | --- | --- | --- | --- | | `totals` | [object](#response-totals) | Yes | Credit deducted in the window, from the credit ledger. | | `items` | array of [Usage entry](#usage-entry-response-items) | Yes | Individual workspace credit charges within the requested time range; totals give the authoritative spending for that period. This operation has no cursor pagination. | ### response.totals | Field | Type | Required | Description | | --- | --- | --- | --- | | `spent_nok` | number | Yes | Usage cost in Norwegian kroner, not øre. | | `deductions` | number | Yes | Credit deductions included in this usage report. | | `by_activity` | array of [object](#response-totals-by-activity) | Yes | Usage totals grouped by activity. | ### response.totals.by_activity[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `activity` | string or null | Yes | Null on a deduction older than the activity column. | | `spent_nok` | number | Yes | Usage cost in Norwegian kroner, not øre. | | `deductions` | number | Yes | Credit deductions included in this usage report. | ### Usage entry · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Identifier for this recorded charge. | | `bundle_id` | null or string | Yes | App or content item associated with this charge, when recorded. | | `timestamp` | number | Yes | Time this charge was recorded, in Unix milliseconds. | | `actor` | string | Yes | Person or automated process responsible for the activity, when recorded. | | `subtype` | null or string | Yes | Activity category associated with this charge, when recorded. | | `credits_deducted_nok` | string | Yes | Workspace credit charged for this activity as a decimal string in Norwegian kroner. Null means a charge was not recorded on this row; use totals for authoritative spending. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | | 403 | `credit_info_hidden` | This workspace plan does not expose credit and usage details. | ## Next steps - [Get billing](/developers/reference/billing/GetBilling) - [List credit ledger](/developers/reference/billing/ListCreditLedger) - [Get storage usage](/developers/reference/billing/GetStorageUsage) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/billing.ListUsage' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{}' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/billing.ListUsage", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/billing.ListUsage", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "totals": { "spent_nok": 0.1, "deductions": 1, "by_activity": [] }, "items": [ { "id": "usage_123", "bundle_id": "document_proposal", "timestamp": 1794301200000, "actor": "account_alex", "subtype": "document_generation", "credits_deducted_nok": "0.10" } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "from": { "type": "integer", "description": "Epoch ms, inclusive." }, "to": { "type": "integer", "description": "Epoch ms, inclusive." } }, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "totals": { "type": "object", "description": "Credit deducted in the window, from the credit ledger.", "properties": { "spent_nok": { "type": "number", "description": "Usage cost in Norwegian kroner, not øre." }, "deductions": { "type": "number", "description": "Credit deductions included in this usage report." }, "by_activity": { "type": "array", "items": { "type": "object", "properties": { "activity": { "type": [ "string", "null" ], "description": "Null on a deduction older than the activity column." }, "spent_nok": { "type": "number", "description": "Usage cost in Norwegian kroner, not øre." }, "deductions": { "type": "number", "description": "Credit deductions included in this usage report." } }, "required": [ "activity", "spent_nok", "deductions" ], "additionalProperties": false }, "description": "Usage totals grouped by activity." } }, "required": [ "spent_nok", "deductions", "by_activity" ], "additionalProperties": false }, "items": { "type": "array", "items": { "title": "Usage entry", "type": "object", "properties": { "id": { "type": "string", "description": "Identifier for this recorded charge.", "examples": [ "usage_123" ] }, "bundle_id": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "App or content item associated with this charge, when recorded.", "examples": [ "document_proposal" ] }, "timestamp": { "type": "number", "description": "Time this charge was recorded, in Unix milliseconds.", "examples": [ 1794301200000 ] }, "actor": { "type": "string", "description": "Person or automated process responsible for the activity, when recorded.", "examples": [ "account_alex" ] }, "subtype": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Activity category associated with this charge, when recorded.", "examples": [ "document_generation" ] }, "credits_deducted_nok": { "type": "string", "description": "Workspace credit charged for this activity as a decimal string in Norwegian kroner. Null means a charge was not recorded on this row; use totals for authoritative spending.", "examples": [ "0.10" ] } }, "required": [ "id", "bundle_id", "timestamp", "actor", "subtype", "credits_deducted_nok" ], "additionalProperties": false }, "description": "Individual workspace credit charges within the requested time range; totals give the authoritative spending for that period. This operation has no cursor pagination." } }, "required": [ "items", "totals" ], "additionalProperties": false, "examples": [ { "totals": { "spent_nok": 0.1, "deductions": 1, "by_activity": [] }, "items": [ { "id": "usage_123", "bundle_id": "document_proposal", "timestamp": 1794301200000, "actor": "account_alex", "subtype": "document_generation", "credits_deducted_nok": "0.10" } ] } ] } ``` --- # Get contact channel Read a contact channel by ID. Returns item: null when no visible record matches. POST https://api.brigg.app/v1/operations/support.GetContactChannel ## Access & visibility Allow `support.GetContactChannel` on your API key. Resource read permissions: `core:ContactChannel`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:ContactChannel` record. Use the relevant list operation to discover records. Use the record's top-level `id`, not a business field or account ID. | ## Response Returns **200 OK** with a JSON body. `item: null` means there is no matching record visible to this caller. It does not reveal whether an inaccessible record exists. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. A contact channel links a communication identity to a Person record; it does not create an inbox or send a message. Use a Person record ID, not a workspace account ID. Supply an email address or international phone number in the channel's canonical form. Creating or linking a channel is not proof that the person controls that address. verified_at is maintained by the verification workflow and is not writable through these record operations. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [ContactChannelRecord](#contactchannelrecord-response-item) or null | Yes | null when no such record | ### ContactChannelRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:ContactChannel record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [ContactChannel](#contactchannel-response-item-data) | Yes | The record's fields. | ### ContactChannel · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Channel identity type: email, phone, web_cookie, sms or other. Allowed: `"email"`, `"phone"`, `"web_cookie"`, `"sms"`, `"other"`. | | `address` | string | Yes | Channel address: a normalized email address, international phone number or channel-specific identifier. This is not a postal address. | | `person_ref` | string | Yes | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `verified_at` | number | No | Time control of this channel address was verified, in Unix milliseconds. May be absent when verification has not been recorded. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [List contact channels](/developers/reference/support/ListContactChannels) - [Create contact channel](/developers/reference/support/CreateContactChannel) - [Upsert contact channel](/developers/reference/support/UpsertContactChannel) - [Update contact channel](/developers/reference/support/UpdateContactChannel) - [Delete contact channel](/developers/reference/support/DeleteContactChannel) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.GetContactChannel' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "e_contactchannel_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/support.GetContactChannel", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "id": "e_contactchannel_example" }), }); 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 payload = { "id": "e_contactchannel_example" } request = Request( "https://api.brigg.app/v1/operations/support.GetContactChannel", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "item": { "id": "e_contactchannel_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "kind": "email", "address": "alex@example.org", "person_ref": "e_person_alex" } } } ``` ### No visible record A missing or inaccessible record returns item: null. Do not treat this as proof that a record exists for another member. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.GetContactChannel' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "e_contactchannel_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/support.GetContactChannel", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "id": "e_contactchannel_example" }), }); 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 payload = { "id": "e_contactchannel_example" } request = Request( "https://api.brigg.app/v1/operations/support.GetContactChannel", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "item": null } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:ContactChannel` record. Use the relevant list operation to discover records. Use the record's top-level `id`, not a business field or account ID." } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_contactchannel_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": [ "object", "null" ], "properties": { "id": { "type": "string", "description": "Stable core:ContactChannel record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "kind": { "type": "string", "enum": [ "email", "phone", "web_cookie", "sms", "other" ], "description": "Channel identity type: email, phone, web_cookie, sms or other." }, "address": { "type": "string", "description": "Channel address: a normalized email address, international phone number or channel-specific identifier. This is not a postal address." }, "person_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "verified_at": { "type": "number", "description": "Time control of this channel address was verified, in Unix milliseconds. May be absent when verification has not been recorded." } }, "required": [ "kind", "address", "person_ref" ], "additionalProperties": false, "description": "The record's fields.", "title": "ContactChannel" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "null when no such record", "title": "ContactChannelRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_contactchannel_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "kind": "email", "address": "alex@example.org", "person_ref": "e_person_alex" } } } ] } ``` --- # List contact channels List contact channels visible to the credential, with filtering, sorting and cursor pagination. POST https://api.brigg.app/v1/operations/support.ListContactChannels ## Access & visibility Allow `support.ListContactChannels` on your API key. Resource read permissions: `core:ContactChannel`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `filters` | array of [object](#request-filters) | No | Conditions the row must ALL satisfy. | | `sort` | [object](#request-sort) | No | Sort order for the results. Defaults to updated_at descending, with id as a tie-breaker. | | `limit` | integer | No | Maximum number of results to return in this page. Continue with next_cursor when returned. Default: `100`. Minimum: 1. | | `cursor` | string | No | The `next_cursor` of the previous page. | ### request.filters[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | `data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private. Allowed: `"id"`, `"created_at"`, `"updated_at"`, `"created_by"`, `"private"`, `"data.kind"`, `"data.address"`, `"data.person_ref"`, `"data.verified_at"`. | | `op` | string | Yes | Comparison operator. Use in with an array, or omit value for is_empty and is_not_empty. Allowed: `"eq"`, `"neq"`, `"contains"`, `"starts_with"`, `"gt"`, `"gte"`, `"lt"`, `"lte"`, `"in"`, `"has"`, `"is_empty"`, `"is_not_empty"`. | | `value` | JSON value | No | The comparison value; an array for `in`; omitted for is_empty / is_not_empty. | ### request.sort | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | `data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private. Allowed: `"id"`, `"created_at"`, `"updated_at"`, `"created_by"`, `"private"`, `"data.kind"`, `"data.address"`, `"data.person_ref"`, `"data.verified_at"`. | | `direction` | string | No | Sort direction: asc for ascending or desc for descending. Allowed: `"asc"`, `"desc"`. | ## Filtering and sorting All conditions are combined with **AND**. Address business fields as `data.`, and record metadata as `id`, `created_at`, `updated_at`, `created_by` or `private`. A field path names one field; it does not traverse nested objects. | Operator | Meaning | Value | | --- | --- | --- | | `eq` | Equal to a scalar | String, number, boolean or null | | `neq` | Not equal; missing values also match | String, number, boolean or null | | `contains` | Case-insensitive text contains | String; % and _ are literal characters | | `starts_with` | Case-insensitive text prefix | String | | `gt`, `gte` | Greater than / at least | Number or string appropriate to the field | | `lt`, `lte` | Less than / at most | Number or string appropriate to the field | | `in` | Equal to any supplied scalar | Nonempty array of strings, numbers, booleans or null | | `has` | Array contains a string | One string; does not match properties inside array objects | | `is_empty` | Missing, null, empty string or empty array | Omit value | | `is_not_empty` | Has a nonempty value | Omit value | Match the stored field's type. Numeric business timestamps take Unix milliseconds; date-only business fields take `YYYY-MM-DD`. The record metadata fields `created_at` and `updated_at` also accept ISO timestamps for ordered comparisons. Sorting defaults to `updated_at` descending. If you supply `sort.field` without `sort.direction`, direction is `desc`. The record ID breaks ties; missing values sort last. ## Response Returns **200 OK** with a JSON body. An empty `items` array means this page contains no matching visible results. Follow `next_cursor` when present. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. A contact channel links a communication identity to a Person record; it does not create an inbox or send a message. Use a Person record ID, not a workspace account ID. Supply an email address or international phone number in the channel's canonical form. Creating or linking a channel is not proof that the person controls that address. verified_at is maintained by the verification workflow and is not writable through these record operations. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [ContactChannelRecord](#contactchannelrecord-response-items) | Yes | Records visible under the credential's grants and the selected data scope, matching the requested filters. Pass next_cursor as cursor to continue when a next cursor is returned. | | `next_cursor` | string | No | Pass this value as cursor to continue with the same filters, sort and credential. Omitted when there are no more results. | ### ContactChannelRecord · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:ContactChannel record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [ContactChannel](#contactchannel-response-items-data) | Yes | The record's fields. | ### ContactChannel · response.items[].data | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Channel identity type: email, phone, web_cookie, sms or other. Allowed: `"email"`, `"phone"`, `"web_cookie"`, `"sms"`, `"other"`. | | `address` | string | Yes | Channel address: a normalized email address, international phone number or channel-specific identifier. This is not a postal address. | | `person_ref` | string | Yes | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `verified_at` | number | No | Time control of this channel address was verified, in Unix milliseconds. May be absent when verification has not been recorded. | ## Pagination Pass `next_cursor` from the response as `cursor` on the next request. Keep the same filters, sort and acting identity. Stop when `next_cursor` is absent; do not infer completion from the number of items. The default page size is **100**; `limit` must be a positive integer. **Pagination is a live view, not a snapshot.** Changes between pages can move records across page boundaries. Upsert by record ID rather than appending blindly. For recurring synchronization, use an overlapping update window and deduplicate records. Periodically reconcile IDs to detect deletions. [Resource webhooks](/developers/webhooks) can supplement synchronization for eligible workspace-shared records only: they do not export private or project-scoped records. Personal data still needs polling and reconciliation. ```typescript const query = { "limit": 10 }; let cursor; do { const response = await fetch("https://api.brigg.app/v1/operations/support.ListContactChannels", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ ...query, ...(cursor ? { cursor } : {}) }), }); const page = await response.json(); if (!response.ok) throw new Error(`${response.status}: ${page.message}`); for (const item of page.items) { console.log(item); // Process or upsert each result. } cursor = page.next_cursor; } while (cursor); ``` ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | | 400 | `cursor_invalid` | Restart pagination with no cursor. | | 400 | `cursor_mismatch` | Use the cursor with the original filters, sort order and credential. | ## Next steps - [Get contact channel](/developers/reference/support/GetContactChannel) - [Create contact channel](/developers/reference/support/CreateContactChannel) - [Upsert contact channel](/developers/reference/support/UpsertContactChannel) - [Update contact channel](/developers/reference/support/UpdateContactChannel) - [Delete contact channel](/developers/reference/support/DeleteContactChannel) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### First page Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.ListContactChannels' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "limit": 10 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/support.ListContactChannels", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "limit": 10 }), }); 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 payload = { "limit": 10 } request = Request( "https://api.brigg.app/v1/operations/support.ListContactChannels", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_contactchannel_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "kind": "email", "address": "alex@example.org", "person_ref": "e_person_alex" } } ] } ``` ### Find a contact by email address Use the normalized address stored by Brigg. The result's person_ref is a customer Person record ID. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.ListContactChannels' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "limit": 50, "filters": [ { "field": "data.address", "op": "eq", "value": "alex@example.org" } ] }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/support.ListContactChannels", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "limit": 50, "filters": [ { "field": "data.address", "op": "eq", "value": "alex@example.org" } ] }), }); 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 payload = { "limit": 50, "filters": [ { "field": "data.address", "op": "eq", "value": "alex@example.org" } ] } request = Request( "https://api.brigg.app/v1/operations/support.ListContactChannels", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_contactchannel_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "kind": "email", "address": "alex@example.org", "person_ref": "e_person_alex" } } ] } ``` ### Records updated since a checkpoint 6 October 2026 at 00:00 UTC. Use an overlap window and upsert by ID when synchronizing. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.ListContactChannels' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/support.ListContactChannels", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 }), }); 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 payload = { "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 } request = Request( "https://api.brigg.app/v1/operations/support.ListContactChannels", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_contactchannel_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "kind": "email", "address": "alex@example.org", "person_ref": "e_person_alex" } } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "filters": { "type": "array", "items": { "type": "object", "properties": { "field": { "type": "string", "description": "`data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private.", "enum": [ "id", "created_at", "updated_at", "created_by", "private", "data.kind", "data.address", "data.person_ref", "data.verified_at" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "contains", "starts_with", "gt", "gte", "lt", "lte", "in", "has", "is_empty", "is_not_empty" ], "description": "Comparison operator. Use in with an array, or omit value for is_empty and is_not_empty." }, "value": { "description": "The comparison value; an array for `in`; omitted for is_empty / is_not_empty." } }, "required": [ "field", "op" ], "additionalProperties": false }, "description": "Conditions the row must ALL satisfy." }, "sort": { "type": "object", "properties": { "field": { "type": "string", "description": "`data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private.", "enum": [ "id", "created_at", "updated_at", "created_by", "private", "data.kind", "data.address", "data.person_ref", "data.verified_at" ] }, "direction": { "type": "string", "enum": [ "asc", "desc" ], "description": "Sort direction: asc for ascending or desc for descending." } }, "required": [ "field" ], "additionalProperties": false, "description": "Sort order for the results. Defaults to updated_at descending, with id as a tie-breaker." }, "limit": { "type": "integer", "minimum": 1, "default": 100, "description": "Maximum number of results to return in this page. Continue with next_cursor when returned." }, "cursor": { "type": "string", "description": "The `next_cursor` of the previous page." } }, "additionalProperties": false, "examples": [ { "limit": 10 } ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:ContactChannel record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "kind": { "type": "string", "enum": [ "email", "phone", "web_cookie", "sms", "other" ], "description": "Channel identity type: email, phone, web_cookie, sms or other." }, "address": { "type": "string", "description": "Channel address: a normalized email address, international phone number or channel-specific identifier. This is not a postal address." }, "person_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "verified_at": { "type": "number", "description": "Time control of this channel address was verified, in Unix milliseconds. May be absent when verification has not been recorded." } }, "required": [ "kind", "address", "person_ref" ], "additionalProperties": false, "description": "The record's fields.", "title": "ContactChannel" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "title": "ContactChannelRecord" }, "description": "Records visible under the credential's grants and the selected data scope, matching the requested filters. Pass next_cursor as cursor to continue when a next cursor is returned." }, "next_cursor": { "type": "string", "description": "Pass this value as cursor to continue with the same filters, sort and credential. Omitted when there are no more results." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "id": "e_contactchannel_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "kind": "email", "address": "alex@example.org", "person_ref": "e_person_alex" } } ] } ] } ``` --- # Create contact channel Create a contact channel and return the saved record. POST https://api.brigg.app/v1/operations/support.CreateContactChannel ## Access & visibility Allow `support.CreateContactChannel` on your API key. Resource read permissions: `core:ContactChannel`. Resource write permissions: `core:ContactChannel`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `data` | [ContactChannel](#contactchannel-request-data) | Yes | The record's fields. | | `private` | boolean | No | Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance. | ### ContactChannel · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Channel identity type: email, phone, web_cookie, sms or other. Allowed: `"email"`, `"phone"`, `"web_cookie"`, `"sms"`, `"other"`. | | `address` | string | Yes | Channel address: a normalized email address, international phone number or channel-specific identifier. This is not a postal address. | | `person_ref` | string | Yes | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | ## Choose ownership deliberately Omitting `private`, or setting it to false, creates a workspace-shared record. Set `private: true` to create a record owned by the approved acting member. Private records require member delegation; a workspace-only credential cannot own a personal record. The credential’s exact resource grants authorize the write; private ownership and project membership remain enforced. A create is a new record, not an upsert. Reuse the same idempotency key only for retries of that logical creation. For recurring synchronization, use the resource’s upsert operation when available: it matches a permanent external reference. Otherwise keep the returned record ID and use the corresponding update operation for subsequent changes. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. A contact channel links a communication identity to a Person record; it does not create an inbox or send a message. Use a Person record ID, not a workspace account ID. Supply an email address or international phone number in the channel's canonical form. Creating or linking a channel is not proof that the person controls that address. verified_at is maintained by the verification workflow and is not writable through these record operations. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [ContactChannelRecord](#contactchannelrecord-response-item) | Yes | The requested record, including its metadata and data fields. | ### ContactChannelRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:ContactChannel record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [ContactChannel](#contactchannel-response-item-data) | Yes | The record's fields. | ### ContactChannel · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Channel identity type: email, phone, web_cookie, sms or other. Allowed: `"email"`, `"phone"`, `"web_cookie"`, `"sms"`, `"other"`. | | `address` | string | Yes | Channel address: a normalized email address, international phone number or channel-specific identifier. This is not a postal address. | | `person_ref` | string | Yes | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `verified_at` | number | No | Time control of this channel address was verified, in Unix milliseconds. May be absent when verification has not been recorded. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List contact channels](/developers/reference/support/ListContactChannels) - [Get contact channel](/developers/reference/support/GetContactChannel) - [Upsert contact channel](/developers/reference/support/UpsertContactChannel) - [Update contact channel](/developers/reference/support/UpdateContactChannel) - [Delete contact channel](/developers/reference/support/DeleteContactChannel) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.CreateContactChannel' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "data": { "kind": "email", "address": "alex@example.org", "person_ref": "e_person_alex" } }' ``` #### TypeScript ```typescript 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/support.CreateContactChannel", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "data": { "kind": "email", "address": "alex@example.org", "person_ref": "e_person_alex" } }), }); 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 = { "data": { "kind": "email", "address": "alex@example.org", "person_ref": "e_person_alex" } } request = Request( "https://api.brigg.app/v1/operations/support.CreateContactChannel", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_contactchannel_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "kind": "email", "address": "alex@example.org", "person_ref": "e_person_alex" } } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "data": { "type": "object", "properties": { "kind": { "type": "string", "enum": [ "email", "phone", "web_cookie", "sms", "other" ], "description": "Channel identity type: email, phone, web_cookie, sms or other." }, "address": { "type": "string", "description": "Channel address: a normalized email address, international phone number or channel-specific identifier. This is not a postal address." }, "person_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." } }, "required": [ "kind", "address", "person_ref" ], "additionalProperties": false, "description": "The record's fields.", "title": "ContactChannel" }, "private": { "type": "boolean", "description": "Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance." } }, "required": [ "data" ], "additionalProperties": false, "examples": [ { "data": { "kind": "email", "address": "alex@example.org", "person_ref": "e_person_alex" } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:ContactChannel record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "kind": { "type": "string", "enum": [ "email", "phone", "web_cookie", "sms", "other" ], "description": "Channel identity type: email, phone, web_cookie, sms or other." }, "address": { "type": "string", "description": "Channel address: a normalized email address, international phone number or channel-specific identifier. This is not a postal address." }, "person_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "verified_at": { "type": "number", "description": "Time control of this channel address was verified, in Unix milliseconds. May be absent when verification has not been recorded." } }, "required": [ "kind", "address", "person_ref" ], "additionalProperties": false, "description": "The record's fields.", "title": "ContactChannel" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "ContactChannelRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_contactchannel_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "kind": "email", "address": "alex@example.org", "person_ref": "e_person_alex" } } } ] } ``` --- # Delete contact channel Delete a contact channel by ID. Repeating a deletion returns already_deleted. POST https://api.brigg.app/v1/operations/support.DeleteContactChannel ## Access & visibility Allow `support.DeleteContactChannel` on your API key. Resource read permissions: `core:ContactChannel`. Resource write permissions: `core:ContactChannel`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:ContactChannel` record. Use the relevant list operation to discover records. Use the record's top-level `id`, not a business field or account ID. | | `expected` | [object](#request-expected) | No | Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {"$absent":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource. | ### request.expected | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string or [object](#request-expected-kind) | No | Commit only if the previous kind value matches; use $absent to require that this field is missing. | | `address` | string or [object](#request-expected-address) | No | Commit only if the previous address value matches; use $absent to require that this field is missing. | | `person_ref` | string or [object](#request-expected-person-ref) | No | Commit only if the previous person_ref value matches; use $absent to require that this field is missing. | | `verified_at` | number or [object](#request-expected-verified-at) | No | Commit only if the previous verified_at value matches; use $absent to require that this field is missing. | ### request.expected.kind | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.address | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.person_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.verified_at | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ## Deletion and retries A successful response reports whether this call removed the record or it was already absent. Check `cascaded` for dependent record IDs returned by the operation. Retrying the same action uses the original idempotency key. A successful deletion is not an archive you can restore through this operation. To avoid deleting a record someone has changed, read it first and put the relevant prior business values in `expected`. Keys are relative to `data`, not prefixed with `data.`. Use {"$absent": true} to require a missing field. A mismatch returns 409 conflict; read again and decide whether deletion is still appropriate. A revised action needs a new idempotency key. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `deleted` | string | Yes | deleted when this request removed the record; already_deleted when it was already absent. Allowed: `"deleted"`, `"already_deleted"`. | | `cascaded` | array of string | No | IDs of dependent records deleted with this 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `conflict` | A supplied expected value no longer matches. Read the record again before deciding whether to retry. | ## Next steps - [List contact channels](/developers/reference/support/ListContactChannels) - [Get contact channel](/developers/reference/support/GetContactChannel) - [Create contact channel](/developers/reference/support/CreateContactChannel) - [Upsert contact channel](/developers/reference/support/UpsertContactChannel) - [Update contact channel](/developers/reference/support/UpdateContactChannel) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.DeleteContactChannel' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_contactchannel_example" }' ``` #### TypeScript ```typescript 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/support.DeleteContactChannel", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_contactchannel_example" }), }); 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_contactchannel_example" } request = Request( "https://api.brigg.app/v1/operations/support.DeleteContactChannel", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "deleted": "deleted" } ``` ### Delete only if unchanged Use a value you actually read. A concurrent change refuses the write with 409 conflict. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.DeleteContactChannel' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_contactchannel_example", "expected": { "kind": "email" } }' ``` #### TypeScript ```typescript 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/support.DeleteContactChannel", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_contactchannel_example", "expected": { "kind": "email" } }), }); 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_contactchannel_example", "expected": { "kind": "email" } } request = Request( "https://api.brigg.app/v1/operations/support.DeleteContactChannel", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "deleted": "deleted" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:ContactChannel` record. Use the relevant list operation to discover records. Use the record's top-level `id`, not a business field or account ID." }, "expected": { "type": "object", "description": "Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {\"$absent\":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource.", "additionalProperties": false, "properties": { "kind": { "description": "Commit only if the previous kind value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "enum": [ "email", "phone", "web_cookie", "sms", "other" ], "description": "Channel identity type: email, phone, web_cookie, sms or other." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "address": { "description": "Commit only if the previous address value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Channel address: a normalized email address, international phone number or channel-specific identifier. This is not a postal address." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "person_ref": { "description": "Commit only if the previous person_ref value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "verified_at": { "description": "Commit only if the previous verified_at value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "number", "description": "Time control of this channel address was verified, in Unix milliseconds. May be absent when verification has not been recorded." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] } } } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_contactchannel_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "deleted": { "type": "string", "enum": [ "deleted", "already_deleted" ], "description": "deleted when this request removed the record; already_deleted when it was already absent." }, "cascaded": { "type": "array", "items": { "type": "string" }, "description": "IDs of dependent records deleted with this record." } }, "required": [ "deleted" ], "additionalProperties": false, "examples": [ { "deleted": "deleted" } ] } ``` --- # Update contact channel Update a contact channel by ID. Omitted fields stay unchanged; use unset to remove fields and expected to prevent overwriting a concurrent change. POST https://api.brigg.app/v1/operations/support.UpdateContactChannel ## Access & visibility Allow `support.UpdateContactChannel` on your API key. Resource read permissions: `core:ContactChannel`. Resource write permissions: `core:ContactChannel`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:ContactChannel` record. Use the relevant list operation to discover records. Use the record's top-level `id`, not a business field or account ID. | | `data` | [ContactChannel](#contactchannel-request-data) | No | The fields to set. | | `unset` | array of string | No | Keys of `data` to remove. Each item: `"kind"`, `"address"`, `"person_ref"`, `"verified_at"`. | | `expected` | [object](#request-expected) | No | Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {"$absent":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource. | ### ContactChannel · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | No | Channel identity type: email, phone, web_cookie, sms or other. Allowed: `"email"`, `"phone"`, `"web_cookie"`, `"sms"`, `"other"`. | | `address` | string | No | Channel address: a normalized email address, international phone number or channel-specific identifier. This is not a postal address. | | `person_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | ### request.expected | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string or [object](#request-expected-kind) | No | Commit only if the previous kind value matches; use $absent to require that this field is missing. | | `address` | string or [object](#request-expected-address) | No | Commit only if the previous address value matches; use $absent to require that this field is missing. | | `person_ref` | string or [object](#request-expected-person-ref) | No | Commit only if the previous person_ref value matches; use $absent to require that this field is missing. | | `verified_at` | number or [object](#request-expected-verified-at) | No | Commit only if the previous verified_at value matches; use $absent to require that this field is missing. | ### request.expected.kind | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.address | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.person_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.verified_at | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ## Update without losing changes Send only the business fields you want to change in `data`; omitted fields stay unchanged. Use `unset` to remove an optional field. Setting a field to null is a different action and is allowed only when its schema permits null. Use `expected` for a conditional update: supply the values you last read for the fields whose concurrent changes would matter. `{"$absent": true}` expects a missing field. A conflict means you must read the record again and decide how to reconcile the change. Keep the same idempotency key when retrying the original action; use a new key for a revised action. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. A contact channel links a communication identity to a Person record; it does not create an inbox or send a message. Use a Person record ID, not a workspace account ID. Supply an email address or international phone number in the channel's canonical form. Creating or linking a channel is not proof that the person controls that address. verified_at is maintained by the verification workflow and is not writable through these record operations. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [ContactChannelRecord](#contactchannelrecord-response-item) | Yes | The requested record, including its metadata and data fields. | ### ContactChannelRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:ContactChannel record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [ContactChannel](#contactchannel-response-item-data) | Yes | The record's fields. | ### ContactChannel · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Channel identity type: email, phone, web_cookie, sms or other. Allowed: `"email"`, `"phone"`, `"web_cookie"`, `"sms"`, `"other"`. | | `address` | string | Yes | Channel address: a normalized email address, international phone number or channel-specific identifier. This is not a postal address. | | `person_ref` | string | Yes | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `verified_at` | number | No | Time control of this channel address was verified, in Unix milliseconds. May be absent when verification has not been recorded. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `conflict` | A supplied expected value no longer matches. Read the record again before deciding whether to retry. | ## Next steps - [List contact channels](/developers/reference/support/ListContactChannels) - [Get contact channel](/developers/reference/support/GetContactChannel) - [Create contact channel](/developers/reference/support/CreateContactChannel) - [Upsert contact channel](/developers/reference/support/UpsertContactChannel) - [Delete contact channel](/developers/reference/support/DeleteContactChannel) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.UpdateContactChannel' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_contactchannel_example", "data": { "person_ref": "e_person_alex" } }' ``` #### TypeScript ```typescript 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/support.UpdateContactChannel", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_contactchannel_example", "data": { "person_ref": "e_person_alex" } }), }); 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_contactchannel_example", "data": { "person_ref": "e_person_alex" } } request = Request( "https://api.brigg.app/v1/operations/support.UpdateContactChannel", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_contactchannel_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "kind": "email", "address": "alex@example.org", "person_ref": "e_person_alex" } } } ``` ### Update only if unchanged Use a value you actually read. A concurrent change refuses the write with 409 conflict. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.UpdateContactChannel' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_contactchannel_example", "data": { "person_ref": "e_person_alex" }, "expected": { "kind": "email" } }' ``` #### TypeScript ```typescript 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/support.UpdateContactChannel", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_contactchannel_example", "data": { "person_ref": "e_person_alex" }, "expected": { "kind": "email" } }), }); 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_contactchannel_example", "data": { "person_ref": "e_person_alex" }, "expected": { "kind": "email" } } request = Request( "https://api.brigg.app/v1/operations/support.UpdateContactChannel", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_contactchannel_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "kind": "email", "address": "alex@example.org", "person_ref": "e_person_alex" } } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:ContactChannel` record. Use the relevant list operation to discover records. Use the record's top-level `id`, not a business field or account ID." }, "data": { "type": "object", "properties": { "kind": { "type": "string", "enum": [ "email", "phone", "web_cookie", "sms", "other" ], "description": "Channel identity type: email, phone, web_cookie, sms or other." }, "address": { "type": "string", "description": "Channel address: a normalized email address, international phone number or channel-specific identifier. This is not a postal address." }, "person_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." } }, "required": [], "additionalProperties": false, "description": "The fields to set.", "title": "ContactChannel" }, "unset": { "type": "array", "items": { "type": "string", "enum": [ "kind", "address", "person_ref", "verified_at" ] }, "description": "Keys of `data` to remove." }, "expected": { "type": "object", "description": "Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {\"$absent\":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource.", "additionalProperties": false, "properties": { "kind": { "description": "Commit only if the previous kind value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "enum": [ "email", "phone", "web_cookie", "sms", "other" ], "description": "Channel identity type: email, phone, web_cookie, sms or other." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "address": { "description": "Commit only if the previous address value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Channel address: a normalized email address, international phone number or channel-specific identifier. This is not a postal address." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "person_ref": { "description": "Commit only if the previous person_ref value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "verified_at": { "description": "Commit only if the previous verified_at value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "number", "description": "Time control of this channel address was verified, in Unix milliseconds. May be absent when verification has not been recorded." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] } } } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_contactchannel_example", "data": { "person_ref": "e_person_alex" } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:ContactChannel record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "kind": { "type": "string", "enum": [ "email", "phone", "web_cookie", "sms", "other" ], "description": "Channel identity type: email, phone, web_cookie, sms or other." }, "address": { "type": "string", "description": "Channel address: a normalized email address, international phone number or channel-specific identifier. This is not a postal address." }, "person_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "verified_at": { "type": "number", "description": "Time control of this channel address was verified, in Unix milliseconds. May be absent when verification has not been recorded." } }, "required": [ "kind", "address", "person_ref" ], "additionalProperties": false, "description": "The record's fields.", "title": "ContactChannel" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "ContactChannelRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_contactchannel_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "kind": "email", "address": "alex@example.org", "person_ref": "e_person_alex" } } } ] } ``` --- # Upsert contact channel Create or update a contact channel by a permanent external reference. Matching is exact within the workspace, resource type and ownership scope. Supplied fields replace their values; omitted fields stay unchanged. Deleted records are not recreated. POST https://api.brigg.app/v1/operations/support.UpsertContactChannel ## Access & visibility Allow `support.UpsertContactChannel` on your API key. Resource read permissions: `core:ContactChannel`. Resource write permissions: `core:ContactChannel`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `data` | [ContactChannel](#contactchannel-request-data) | Yes | The record's fields. | | `private` | boolean | No | Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance. | | `external_ref` | [object](#request-external-ref) | Yes | Permanent, case-sensitive source identity within this workspace, resource type and private/workspace scope. It is independent of API key rotation and retry receipt expiry. | ### ContactChannel · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Channel identity type: email, phone, web_cookie, sms or other. Allowed: `"email"`, `"phone"`, `"web_cookie"`, `"sms"`, `"other"`. | | `address` | string | Yes | Channel address: a normalized email address, international phone number or channel-specific identifier. This is not a postal address. | | `person_ref` | string | Yes | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | ### request.external_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `namespace` | string | Yes | A stable name for the source system, such as crm-production. At least 1 character. | | `id` | string | Yes | The record ID in that source system. At least 1 character. | ## Sync with a permanent external reference Choose a stable `external_ref.namespace` for your source system and put its record ID in `external_ref.id`. Matching is case-sensitive and scoped to this workspace, resource type and private/workspace ownership. The reference survives API key replacement and the 30-day retry receipt window. It does not match records by email or name. Send the required create fields each time. A missing reference creates a record; an existing reference updates only supplied fields and preserves everything else. `created` tells you which happened. Use the same idempotency key when retrying a lost response and a new key for a later source change. Concurrent calls cannot create duplicate records. A deleted or inaccessible match is refused; the operation does not restore it or make a replacement. Use the returned `item.id` with the regular update operation when you need `unset` or a conditional `expected` edit. Changing `private` chooses a different ownership scope; it does not transfer an existing record. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. A contact channel links a communication identity to a Person record; it does not create an inbox or send a message. Use a Person record ID, not a workspace account ID. Supply an email address or international phone number in the channel's canonical form. Creating or linking a channel is not proof that the person controls that address. verified_at is maintained by the verification workflow and is not writable through these record operations. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [ContactChannelRecord](#contactchannelrecord-response-item) | Yes | The requested record, including its metadata and data fields. | | `created` | boolean | Yes | True when this external reference created a record; false when it matched an existing record. | ### ContactChannelRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:ContactChannel record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [ContactChannel](#contactchannel-response-item-data) | Yes | The record's fields. | ### ContactChannel · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Channel identity type: email, phone, web_cookie, sms or other. Allowed: `"email"`, `"phone"`, `"web_cookie"`, `"sms"`, `"other"`. | | `address` | string | Yes | Channel address: a normalized email address, international phone number or channel-specific identifier. This is not a postal address. | | `person_ref` | string | Yes | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `verified_at` | number | No | Time control of this channel address was verified, in Unix milliseconds. May be absent when verification has not been recorded. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List contact channels](/developers/reference/support/ListContactChannels) - [Get contact channel](/developers/reference/support/GetContactChannel) - [Create contact channel](/developers/reference/support/CreateContactChannel) - [Update contact channel](/developers/reference/support/UpdateContactChannel) - [Delete contact channel](/developers/reference/support/DeleteContactChannel) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### First sync Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.UpsertContactChannel' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "kind": "email", "address": "alex@example.org", "person_ref": "e_person_alex" } }' ``` #### TypeScript ```typescript 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/support.UpsertContactChannel", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "kind": "email", "address": "alex@example.org", "person_ref": "e_person_alex" } }), }); 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 = { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "kind": "email", "address": "alex@example.org", "person_ref": "e_person_alex" } } request = Request( "https://api.brigg.app/v1/operations/support.UpsertContactChannel", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_contactchannel_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "kind": "email", "address": "alex@example.org", "person_ref": "e_person_alex" } }, "created": true } ``` ### Later sync The same external reference returns the same record ID. Use a new idempotency key for a later source change. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.UpsertContactChannel' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "kind": "email", "address": "alex@example.org", "person_ref": "e_person_alex" } }' ``` #### TypeScript ```typescript 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/support.UpsertContactChannel", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "kind": "email", "address": "alex@example.org", "person_ref": "e_person_alex" } }), }); 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 = { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "kind": "email", "address": "alex@example.org", "person_ref": "e_person_alex" } } request = Request( "https://api.brigg.app/v1/operations/support.UpsertContactChannel", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_contactchannel_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "kind": "email", "address": "alex@example.org", "person_ref": "e_person_alex" } }, "created": false } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "data": { "type": "object", "properties": { "kind": { "type": "string", "enum": [ "email", "phone", "web_cookie", "sms", "other" ], "description": "Channel identity type: email, phone, web_cookie, sms or other." }, "address": { "type": "string", "description": "Channel address: a normalized email address, international phone number or channel-specific identifier. This is not a postal address." }, "person_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." } }, "required": [ "kind", "address", "person_ref" ], "additionalProperties": false, "description": "The record's fields.", "title": "ContactChannel" }, "private": { "type": "boolean", "description": "Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance." }, "external_ref": { "type": "object", "description": "Permanent, case-sensitive source identity within this workspace, resource type and private/workspace scope. It is independent of API key rotation and retry receipt expiry.", "properties": { "namespace": { "type": "string", "minLength": 1, "description": "A stable name for the source system, such as crm-production." }, "id": { "type": "string", "minLength": 1, "description": "The record ID in that source system." } }, "required": [ "namespace", "id" ], "additionalProperties": false } }, "required": [ "external_ref", "data" ], "additionalProperties": false, "examples": [ { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "kind": "email", "address": "alex@example.org", "person_ref": "e_person_alex" } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:ContactChannel record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "kind": { "type": "string", "enum": [ "email", "phone", "web_cookie", "sms", "other" ], "description": "Channel identity type: email, phone, web_cookie, sms or other." }, "address": { "type": "string", "description": "Channel address: a normalized email address, international phone number or channel-specific identifier. This is not a postal address." }, "person_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "verified_at": { "type": "number", "description": "Time control of this channel address was verified, in Unix milliseconds. May be absent when verification has not been recorded." } }, "required": [ "kind", "address", "person_ref" ], "additionalProperties": false, "description": "The record's fields.", "title": "ContactChannel" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "ContactChannelRecord" }, "created": { "type": "boolean", "description": "True when this external reference created a record; false when it matched an existing record." } }, "required": [ "item", "created" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_contactchannel_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "kind": "email", "address": "alex@example.org", "person_ref": "e_person_alex" } }, "created": true } ] } ``` --- # Get conversation Read a conversation by ID. Returns item: null when no visible record matches. POST https://api.brigg.app/v1/operations/support.GetConversation ## Access & visibility Allow `support.GetConversation` on your API key. Resource read permissions: `core:Conversation`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:Conversation` record. Find it with [support.ListConversations](/developers/reference/support/ListConversations). Use the record's top-level `id`, not a business field or account ID. | ## Response Returns **200 OK** with a JSON body. `item: null` means there is no matching record visible to this caller. It does not reveal whether an inaccessible record exists. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [ConversationRecord](#conversationrecord-response-item) or null | Yes | null when no such record | ### ConversationRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Conversation record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Conversation](#conversation-response-item-data) | Yes | The record's fields. | ### Conversation · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `inbox_ref` | string | No | ID of a `core:Inbox` record. Find it with [support.ListInboxes](/developers/reference/support/ListInboxes) and use the top-level `id`. This is not an account ID or a display name. | | `subject` | string | No | Conversation subject shown to the support team. | | `contact_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `company_ref` | string | No | ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name. | | `status` | string | No | Current case state. Resolved and closed are distinct stored states; use the value returned by the API. Allowed: `"new"`, `"open"`, `"pending"`, `"escalated"`, `"snoozed"`, `"resolved"`, `"closed"`. | | `assignee_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `channel` | string | No | Channel through which this conversation arrived. Allowed: `"email"`, `"web_chat"`, `"contact_form"`, `"sms"`, `"phone"`. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | | `snippet` | string | No | Short preview of the conversation's latest message. | | `last_message_at` | number | No | Most recent message time in Unix milliseconds. | | `first_response_at` | number | No | First response time in Unix milliseconds, when a response has been recorded. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [List conversations](/developers/reference/support/ListConversations) - [Create conversation](/developers/reference/support/CreateConversation) - [Upsert conversation](/developers/reference/support/UpsertConversation) - [Update conversation](/developers/reference/support/UpdateConversation) - [Delete conversation](/developers/reference/support/DeleteConversation) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.GetConversation' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "e_conversation_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/support.GetConversation", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "id": "e_conversation_example" }), }); 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 payload = { "id": "e_conversation_example" } request = Request( "https://api.brigg.app/v1/operations/support.GetConversation", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "item": { "id": "e_conversation_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "inbox_ref": "e_inbox_support", "subject": "Help with onboarding", "contact_ref": "e_person_alex", "status": "open", "channel": "email", "snippet": "Can you help us import our contacts?", "last_message_at": 1791279900000 } } } ``` ### No visible record A missing or inaccessible record returns item: null. Do not treat this as proof that a record exists for another member. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.GetConversation' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "e_conversation_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/support.GetConversation", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "id": "e_conversation_example" }), }); 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 payload = { "id": "e_conversation_example" } request = Request( "https://api.brigg.app/v1/operations/support.GetConversation", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "item": null } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:Conversation` record. Find it with [support.ListConversations](/developers/reference/support/ListConversations). Use the record's top-level `id`, not a business field or account ID." } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_conversation_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": [ "object", "null" ], "properties": { "id": { "type": "string", "description": "Stable core:Conversation record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "inbox_ref": { "type": "string", "description": "ID of a `core:Inbox` record. Find it with [support.ListInboxes](/developers/reference/support/ListInboxes) and use the top-level `id`. This is not an account ID or a display name." }, "subject": { "type": "string", "description": "Conversation subject shown to the support team." }, "contact_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "company_ref": { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." }, "status": { "type": "string", "enum": [ "new", "open", "pending", "escalated", "snoozed", "resolved", "closed" ], "description": "Current case state. Resolved and closed are distinct stored states; use the value returned by the API." }, "assignee_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "channel": { "type": "string", "enum": [ "email", "web_chat", "contact_form", "sms", "phone" ], "description": "Channel through which this conversation arrived." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, "snippet": { "type": "string", "description": "Short preview of the conversation's latest message." }, "last_message_at": { "type": "number", "description": "Most recent message time in Unix milliseconds." }, "first_response_at": { "type": "number", "description": "First response time in Unix milliseconds, when a response has been recorded." } }, "additionalProperties": false, "description": "The record's fields.", "title": "Conversation" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "null when no such record", "title": "ConversationRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_conversation_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "inbox_ref": "e_inbox_support", "subject": "Help with onboarding", "contact_ref": "e_person_alex", "status": "open", "channel": "email", "snippet": "Can you help us import our contacts?", "last_message_at": 1791279900000 } } } ] } ``` --- # List conversations List conversations visible to the credential, with filtering, sorting and cursor pagination. POST https://api.brigg.app/v1/operations/support.ListConversations ## Access & visibility Allow `support.ListConversations` on your API key. Resource read permissions: `core:Conversation`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `filters` | array of [object](#request-filters) | No | Conditions the row must ALL satisfy. | | `sort` | [object](#request-sort) | No | Sort order for the results. Defaults to updated_at descending, with id as a tie-breaker. | | `limit` | integer | No | Maximum number of results to return in this page. Continue with next_cursor when returned. Default: `100`. Minimum: 1. | | `cursor` | string | No | The `next_cursor` of the previous page. | ### request.filters[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | `data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private. Allowed: `"id"`, `"created_at"`, `"updated_at"`, `"created_by"`, `"private"`, `"data.inbox_ref"`, `"data.subject"`, `"data.contact_ref"`, `"data.company_ref"`, `"data.status"`, `"data.assignee_ref"`, `"data.channel"`, `"data.tags"`, `"data.snippet"`, `"data.last_message_at"`, `"data.first_response_at"`. | | `op` | string | Yes | Comparison operator. Use in with an array, or omit value for is_empty and is_not_empty. Allowed: `"eq"`, `"neq"`, `"contains"`, `"starts_with"`, `"gt"`, `"gte"`, `"lt"`, `"lte"`, `"in"`, `"has"`, `"is_empty"`, `"is_not_empty"`. | | `value` | JSON value | No | The comparison value; an array for `in`; omitted for is_empty / is_not_empty. | ### request.sort | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | `data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private. Allowed: `"id"`, `"created_at"`, `"updated_at"`, `"created_by"`, `"private"`, `"data.inbox_ref"`, `"data.subject"`, `"data.contact_ref"`, `"data.company_ref"`, `"data.status"`, `"data.assignee_ref"`, `"data.channel"`, `"data.tags"`, `"data.snippet"`, `"data.last_message_at"`, `"data.first_response_at"`. | | `direction` | string | No | Sort direction: asc for ascending or desc for descending. Allowed: `"asc"`, `"desc"`. | ## Filtering and sorting All conditions are combined with **AND**. Address business fields as `data.`, and record metadata as `id`, `created_at`, `updated_at`, `created_by` or `private`. A field path names one field; it does not traverse nested objects. | Operator | Meaning | Value | | --- | --- | --- | | `eq` | Equal to a scalar | String, number, boolean or null | | `neq` | Not equal; missing values also match | String, number, boolean or null | | `contains` | Case-insensitive text contains | String; % and _ are literal characters | | `starts_with` | Case-insensitive text prefix | String | | `gt`, `gte` | Greater than / at least | Number or string appropriate to the field | | `lt`, `lte` | Less than / at most | Number or string appropriate to the field | | `in` | Equal to any supplied scalar | Nonempty array of strings, numbers, booleans or null | | `has` | Array contains a string | One string; does not match properties inside array objects | | `is_empty` | Missing, null, empty string or empty array | Omit value | | `is_not_empty` | Has a nonempty value | Omit value | Match the stored field's type. Numeric business timestamps take Unix milliseconds; date-only business fields take `YYYY-MM-DD`. The record metadata fields `created_at` and `updated_at` also accept ISO timestamps for ordered comparisons. Sorting defaults to `updated_at` descending. If you supply `sort.field` without `sort.direction`, direction is `desc`. The record ID breaks ties; missing values sort last. ## Response Returns **200 OK** with a JSON body. An empty `items` array means this page contains no matching visible results. Follow `next_cursor` when present. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [ConversationRecord](#conversationrecord-response-items) | Yes | Records visible under the credential's grants and the selected data scope, matching the requested filters. Pass next_cursor as cursor to continue when a next cursor is returned. | | `next_cursor` | string | No | Pass this value as cursor to continue with the same filters, sort and credential. Omitted when there are no more results. | ### ConversationRecord · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Conversation record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Conversation](#conversation-response-items-data) | Yes | The record's fields. | ### Conversation · response.items[].data | Field | Type | Required | Description | | --- | --- | --- | --- | | `inbox_ref` | string | No | ID of a `core:Inbox` record. Find it with [support.ListInboxes](/developers/reference/support/ListInboxes) and use the top-level `id`. This is not an account ID or a display name. | | `subject` | string | No | Conversation subject shown to the support team. | | `contact_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `company_ref` | string | No | ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name. | | `status` | string | No | Current case state. Resolved and closed are distinct stored states; use the value returned by the API. Allowed: `"new"`, `"open"`, `"pending"`, `"escalated"`, `"snoozed"`, `"resolved"`, `"closed"`. | | `assignee_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `channel` | string | No | Channel through which this conversation arrived. Allowed: `"email"`, `"web_chat"`, `"contact_form"`, `"sms"`, `"phone"`. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | | `snippet` | string | No | Short preview of the conversation's latest message. | | `last_message_at` | number | No | Most recent message time in Unix milliseconds. | | `first_response_at` | number | No | First response time in Unix milliseconds, when a response has been recorded. | ## Pagination Pass `next_cursor` from the response as `cursor` on the next request. Keep the same filters, sort and acting identity. Stop when `next_cursor` is absent; do not infer completion from the number of items. The default page size is **100**; `limit` must be a positive integer. **Pagination is a live view, not a snapshot.** Changes between pages can move records across page boundaries. Upsert by record ID rather than appending blindly. For recurring synchronization, use an overlapping update window and deduplicate records. Periodically reconcile IDs to detect deletions. [Resource webhooks](/developers/webhooks) can supplement synchronization for eligible workspace-shared records only: they do not export private or project-scoped records. Personal data still needs polling and reconciliation. ```typescript const query = { "limit": 10 }; let cursor; do { const response = await fetch("https://api.brigg.app/v1/operations/support.ListConversations", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ ...query, ...(cursor ? { cursor } : {}) }), }); const page = await response.json(); if (!response.ok) throw new Error(`${response.status}: ${page.message}`); for (const item of page.items) { console.log(item); // Process or upsert each result. } cursor = page.next_cursor; } while (cursor); ``` ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | | 400 | `cursor_invalid` | Restart pagination with no cursor. | | 400 | `cursor_mismatch` | Use the cursor with the original filters, sort order and credential. | ## Next steps - [Get conversation](/developers/reference/support/GetConversation) - [Create conversation](/developers/reference/support/CreateConversation) - [Upsert conversation](/developers/reference/support/UpsertConversation) - [Update conversation](/developers/reference/support/UpdateConversation) - [Delete conversation](/developers/reference/support/DeleteConversation) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### First page Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.ListConversations' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "limit": 10 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/support.ListConversations", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "limit": 10 }), }); 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 payload = { "limit": 10 } request = Request( "https://api.brigg.app/v1/operations/support.ListConversations", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_conversation_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "inbox_ref": "e_inbox_support", "subject": "Help with onboarding", "contact_ref": "e_person_alex", "status": "open", "channel": "email", "snippet": "Can you help us import our contacts?", "last_message_at": 1791279900000 } } ] } ``` ### Open cases in one inbox Get the inbox ID from List inboxes. new and open are separate statuses; include both when building a work queue. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.ListConversations' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "limit": 50, "filters": [ { "field": "data.inbox_ref", "op": "eq", "value": "e_inbox_support" }, { "field": "data.status", "op": "in", "value": [ "new", "open" ] } ], "sort": { "field": "data.last_message_at", "direction": "desc" } }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/support.ListConversations", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "limit": 50, "filters": [ { "field": "data.inbox_ref", "op": "eq", "value": "e_inbox_support" }, { "field": "data.status", "op": "in", "value": [ "new", "open" ] } ], "sort": { "field": "data.last_message_at", "direction": "desc" } }), }); 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 payload = { "limit": 50, "filters": [ { "field": "data.inbox_ref", "op": "eq", "value": "e_inbox_support" }, { "field": "data.status", "op": "in", "value": [ "new", "open" ] } ], "sort": { "field": "data.last_message_at", "direction": "desc" } } request = Request( "https://api.brigg.app/v1/operations/support.ListConversations", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_conversation_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "inbox_ref": "e_inbox_support", "subject": "Help with onboarding", "contact_ref": "e_person_alex", "status": "open", "channel": "email", "snippet": "Can you help us import our contacts?", "last_message_at": 1791279900000 } } ] } ``` ### Records updated since a checkpoint 6 October 2026 at 00:00 UTC. Use an overlap window and upsert by ID when synchronizing. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.ListConversations' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/support.ListConversations", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 }), }); 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 payload = { "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 } request = Request( "https://api.brigg.app/v1/operations/support.ListConversations", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_conversation_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "inbox_ref": "e_inbox_support", "subject": "Help with onboarding", "contact_ref": "e_person_alex", "status": "open", "channel": "email", "snippet": "Can you help us import our contacts?", "last_message_at": 1791279900000 } } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "filters": { "type": "array", "items": { "type": "object", "properties": { "field": { "type": "string", "description": "`data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private.", "enum": [ "id", "created_at", "updated_at", "created_by", "private", "data.inbox_ref", "data.subject", "data.contact_ref", "data.company_ref", "data.status", "data.assignee_ref", "data.channel", "data.tags", "data.snippet", "data.last_message_at", "data.first_response_at" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "contains", "starts_with", "gt", "gte", "lt", "lte", "in", "has", "is_empty", "is_not_empty" ], "description": "Comparison operator. Use in with an array, or omit value for is_empty and is_not_empty." }, "value": { "description": "The comparison value; an array for `in`; omitted for is_empty / is_not_empty." } }, "required": [ "field", "op" ], "additionalProperties": false }, "description": "Conditions the row must ALL satisfy." }, "sort": { "type": "object", "properties": { "field": { "type": "string", "description": "`data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private.", "enum": [ "id", "created_at", "updated_at", "created_by", "private", "data.inbox_ref", "data.subject", "data.contact_ref", "data.company_ref", "data.status", "data.assignee_ref", "data.channel", "data.tags", "data.snippet", "data.last_message_at", "data.first_response_at" ] }, "direction": { "type": "string", "enum": [ "asc", "desc" ], "description": "Sort direction: asc for ascending or desc for descending." } }, "required": [ "field" ], "additionalProperties": false, "description": "Sort order for the results. Defaults to updated_at descending, with id as a tie-breaker." }, "limit": { "type": "integer", "minimum": 1, "default": 100, "description": "Maximum number of results to return in this page. Continue with next_cursor when returned." }, "cursor": { "type": "string", "description": "The `next_cursor` of the previous page." } }, "additionalProperties": false, "examples": [ { "limit": 10 } ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:Conversation record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "inbox_ref": { "type": "string", "description": "ID of a `core:Inbox` record. Find it with [support.ListInboxes](/developers/reference/support/ListInboxes) and use the top-level `id`. This is not an account ID or a display name." }, "subject": { "type": "string", "description": "Conversation subject shown to the support team." }, "contact_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "company_ref": { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." }, "status": { "type": "string", "enum": [ "new", "open", "pending", "escalated", "snoozed", "resolved", "closed" ], "description": "Current case state. Resolved and closed are distinct stored states; use the value returned by the API." }, "assignee_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "channel": { "type": "string", "enum": [ "email", "web_chat", "contact_form", "sms", "phone" ], "description": "Channel through which this conversation arrived." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, "snippet": { "type": "string", "description": "Short preview of the conversation's latest message." }, "last_message_at": { "type": "number", "description": "Most recent message time in Unix milliseconds." }, "first_response_at": { "type": "number", "description": "First response time in Unix milliseconds, when a response has been recorded." } }, "additionalProperties": false, "description": "The record's fields.", "title": "Conversation" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "title": "ConversationRecord" }, "description": "Records visible under the credential's grants and the selected data scope, matching the requested filters. Pass next_cursor as cursor to continue when a next cursor is returned." }, "next_cursor": { "type": "string", "description": "Pass this value as cursor to continue with the same filters, sort and credential. Omitted when there are no more results." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "id": "e_conversation_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "inbox_ref": "e_inbox_support", "subject": "Help with onboarding", "contact_ref": "e_person_alex", "status": "open", "channel": "email", "snippet": "Can you help us import our contacts?", "last_message_at": 1791279900000 } } ] } ] } ``` --- # Create conversation Create a conversation and return the saved record. POST https://api.brigg.app/v1/operations/support.CreateConversation ## Access & visibility Allow `support.CreateConversation` on your API key. Resource read permissions: `core:Conversation`. Resource write permissions: `core:Conversation`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `data` | [Conversation](#conversation-request-data) | Yes | The record's fields. | | `private` | boolean | No | Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance. | ### Conversation · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `inbox_ref` | string | No | ID of a `core:Inbox` record. Find it with [support.ListInboxes](/developers/reference/support/ListInboxes) and use the top-level `id`. This is not an account ID or a display name. | | `subject` | string | No | Conversation subject shown to the support team. | | `contact_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `company_ref` | string | No | ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name. | | `status` | string | No | Current case state. Resolved and closed are distinct stored states; use the value returned by the API. Allowed: `"new"`, `"open"`, `"pending"`, `"escalated"`, `"snoozed"`, `"resolved"`, `"closed"`. | | `assignee_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | ## Choose ownership deliberately Omitting `private`, or setting it to false, creates a workspace-shared record. Set `private: true` to create a record owned by the approved acting member. Private records require member delegation; a workspace-only credential cannot own a personal record. The credential’s exact resource grants authorize the write; private ownership and project membership remain enforced. A create is a new record, not an upsert. Reuse the same idempotency key only for retries of that logical creation. For recurring synchronization, use the resource’s upsert operation when available: it matches a permanent external reference. Otherwise keep the returned record ID and use the corresponding update operation for subsequent changes. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [ConversationRecord](#conversationrecord-response-item) | Yes | The requested record, including its metadata and data fields. | ### ConversationRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Conversation record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Conversation](#conversation-response-item-data) | Yes | The record's fields. | ### Conversation · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `inbox_ref` | string | No | ID of a `core:Inbox` record. Find it with [support.ListInboxes](/developers/reference/support/ListInboxes) and use the top-level `id`. This is not an account ID or a display name. | | `subject` | string | No | Conversation subject shown to the support team. | | `contact_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `company_ref` | string | No | ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name. | | `status` | string | No | Current case state. Resolved and closed are distinct stored states; use the value returned by the API. Allowed: `"new"`, `"open"`, `"pending"`, `"escalated"`, `"snoozed"`, `"resolved"`, `"closed"`. | | `assignee_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `channel` | string | No | Channel through which this conversation arrived. Allowed: `"email"`, `"web_chat"`, `"contact_form"`, `"sms"`, `"phone"`. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | | `snippet` | string | No | Short preview of the conversation's latest message. | | `last_message_at` | number | No | Most recent message time in Unix milliseconds. | | `first_response_at` | number | No | First response time in Unix milliseconds, when a response has been recorded. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List conversations](/developers/reference/support/ListConversations) - [Get conversation](/developers/reference/support/GetConversation) - [Upsert conversation](/developers/reference/support/UpsertConversation) - [Update conversation](/developers/reference/support/UpdateConversation) - [Delete conversation](/developers/reference/support/DeleteConversation) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.CreateConversation' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "data": { "inbox_ref": "e_inbox_support", "subject": "Help with onboarding", "contact_ref": "e_person_alex", "status": "open" } }' ``` #### TypeScript ```typescript 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/support.CreateConversation", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "data": { "inbox_ref": "e_inbox_support", "subject": "Help with onboarding", "contact_ref": "e_person_alex", "status": "open" } }), }); 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 = { "data": { "inbox_ref": "e_inbox_support", "subject": "Help with onboarding", "contact_ref": "e_person_alex", "status": "open" } } request = Request( "https://api.brigg.app/v1/operations/support.CreateConversation", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_conversation_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "inbox_ref": "e_inbox_support", "subject": "Help with onboarding", "contact_ref": "e_person_alex", "status": "open", "channel": "email", "snippet": "Can you help us import our contacts?", "last_message_at": 1791279900000 } } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "data": { "type": "object", "properties": { "inbox_ref": { "type": "string", "description": "ID of a `core:Inbox` record. Find it with [support.ListInboxes](/developers/reference/support/ListInboxes) and use the top-level `id`. This is not an account ID or a display name." }, "subject": { "type": "string", "description": "Conversation subject shown to the support team." }, "contact_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "company_ref": { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." }, "status": { "type": "string", "enum": [ "new", "open", "pending", "escalated", "snoozed", "resolved", "closed" ], "description": "Current case state. Resolved and closed are distinct stored states; use the value returned by the API." }, "assignee_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." } }, "additionalProperties": false, "description": "The record's fields.", "title": "Conversation" }, "private": { "type": "boolean", "description": "Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance." } }, "required": [ "data" ], "additionalProperties": false, "examples": [ { "data": { "inbox_ref": "e_inbox_support", "subject": "Help with onboarding", "contact_ref": "e_person_alex", "status": "open" } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:Conversation record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "inbox_ref": { "type": "string", "description": "ID of a `core:Inbox` record. Find it with [support.ListInboxes](/developers/reference/support/ListInboxes) and use the top-level `id`. This is not an account ID or a display name." }, "subject": { "type": "string", "description": "Conversation subject shown to the support team." }, "contact_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "company_ref": { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." }, "status": { "type": "string", "enum": [ "new", "open", "pending", "escalated", "snoozed", "resolved", "closed" ], "description": "Current case state. Resolved and closed are distinct stored states; use the value returned by the API." }, "assignee_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "channel": { "type": "string", "enum": [ "email", "web_chat", "contact_form", "sms", "phone" ], "description": "Channel through which this conversation arrived." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, "snippet": { "type": "string", "description": "Short preview of the conversation's latest message." }, "last_message_at": { "type": "number", "description": "Most recent message time in Unix milliseconds." }, "first_response_at": { "type": "number", "description": "First response time in Unix milliseconds, when a response has been recorded." } }, "additionalProperties": false, "description": "The record's fields.", "title": "Conversation" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "ConversationRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_conversation_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "inbox_ref": "e_inbox_support", "subject": "Help with onboarding", "contact_ref": "e_person_alex", "status": "open", "channel": "email", "snippet": "Can you help us import our contacts?", "last_message_at": 1791279900000 } } } ] } ``` --- # Delete conversation Delete a conversation by ID. Repeating a deletion returns already_deleted. POST https://api.brigg.app/v1/operations/support.DeleteConversation ## Access & visibility Allow `support.DeleteConversation` on your API key. Resource read permissions: `core:Conversation`. Resource write permissions: `core:Conversation`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:Conversation` record. Find it with [support.ListConversations](/developers/reference/support/ListConversations). Use the record's top-level `id`, not a business field or account ID. | | `expected` | [object](#request-expected) | No | Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {"$absent":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource. | ### request.expected | Field | Type | Required | Description | | --- | --- | --- | --- | | `inbox_ref` | string or [object](#request-expected-inbox-ref) | No | Commit only if the previous inbox_ref value matches; use $absent to require that this field is missing. | | `subject` | string or [object](#request-expected-subject) | No | Commit only if the previous subject value matches; use $absent to require that this field is missing. | | `contact_ref` | string or [object](#request-expected-contact-ref) | No | Commit only if the previous contact_ref value matches; use $absent to require that this field is missing. | | `company_ref` | string or [object](#request-expected-company-ref) | No | Commit only if the previous company_ref value matches; use $absent to require that this field is missing. | | `status` | string or [object](#request-expected-status) | No | Commit only if the previous status value matches; use $absent to require that this field is missing. | | `assignee_ref` | string or [object](#request-expected-assignee-ref) | No | Commit only if the previous assignee_ref value matches; use $absent to require that this field is missing. | | `channel` | string or [object](#request-expected-channel) | No | Commit only if the previous channel value matches; use $absent to require that this field is missing. | | `tags` | array of string or [object](#request-expected-tags) | No | Commit only if the previous tags value matches; use $absent to require that this field is missing. | | `snippet` | string or [object](#request-expected-snippet) | No | Commit only if the previous snippet value matches; use $absent to require that this field is missing. | | `last_message_at` | number or [object](#request-expected-last-message-at) | No | Commit only if the previous last_message_at value matches; use $absent to require that this field is missing. | | `first_response_at` | number or [object](#request-expected-first-response-at) | No | Commit only if the previous first_response_at value matches; use $absent to require that this field is missing. | ### request.expected.inbox_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.subject | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.contact_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.company_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.status | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.assignee_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.channel | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.tags | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.snippet | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.last_message_at | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.first_response_at | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ## Deletion and retries A successful response reports whether this call removed the record or it was already absent. Check `cascaded` for dependent record IDs returned by the operation. Retrying the same action uses the original idempotency key. A successful deletion is not an archive you can restore through this operation. To avoid deleting a record someone has changed, read it first and put the relevant prior business values in `expected`. Keys are relative to `data`, not prefixed with `data.`. Use {"$absent": true} to require a missing field. A mismatch returns 409 conflict; read again and decide whether deletion is still appropriate. A revised action needs a new idempotency key. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `deleted` | string | Yes | deleted when this request removed the record; already_deleted when it was already absent. Allowed: `"deleted"`, `"already_deleted"`. | | `cascaded` | array of string | No | IDs of dependent records deleted with this 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `conflict` | A supplied expected value no longer matches. Read the record again before deciding whether to retry. | ## Next steps - [List conversations](/developers/reference/support/ListConversations) - [Get conversation](/developers/reference/support/GetConversation) - [Create conversation](/developers/reference/support/CreateConversation) - [Upsert conversation](/developers/reference/support/UpsertConversation) - [Update conversation](/developers/reference/support/UpdateConversation) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.DeleteConversation' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_conversation_example" }' ``` #### TypeScript ```typescript 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/support.DeleteConversation", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_conversation_example" }), }); 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_conversation_example" } request = Request( "https://api.brigg.app/v1/operations/support.DeleteConversation", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "deleted": "deleted" } ``` ### Delete only if unchanged Use a value you actually read. A concurrent change refuses the write with 409 conflict. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.DeleteConversation' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_conversation_example", "expected": { "inbox_ref": "e_inbox_support" } }' ``` #### TypeScript ```typescript 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/support.DeleteConversation", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_conversation_example", "expected": { "inbox_ref": "e_inbox_support" } }), }); 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_conversation_example", "expected": { "inbox_ref": "e_inbox_support" } } request = Request( "https://api.brigg.app/v1/operations/support.DeleteConversation", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "deleted": "deleted" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:Conversation` record. Find it with [support.ListConversations](/developers/reference/support/ListConversations). Use the record's top-level `id`, not a business field or account ID." }, "expected": { "type": "object", "description": "Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {\"$absent\":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource.", "additionalProperties": false, "properties": { "inbox_ref": { "description": "Commit only if the previous inbox_ref value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "ID of a `core:Inbox` record. Find it with [support.ListInboxes](/developers/reference/support/ListInboxes) and use the top-level `id`. This is not an account ID or a display name." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "subject": { "description": "Commit only if the previous subject value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Conversation subject shown to the support team." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "contact_ref": { "description": "Commit only if the previous contact_ref value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "company_ref": { "description": "Commit only if the previous company_ref value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "status": { "description": "Commit only if the previous status value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "enum": [ "new", "open", "pending", "escalated", "snoozed", "resolved", "closed" ], "description": "Current case state. Resolved and closed are distinct stored states; use the value returned by the API." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "assignee_ref": { "description": "Commit only if the previous assignee_ref value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "channel": { "description": "Commit only if the previous channel value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "enum": [ "email", "web_chat", "contact_form", "sms", "phone" ], "description": "Channel through which this conversation arrived." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "tags": { "description": "Commit only if the previous tags value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "snippet": { "description": "Commit only if the previous snippet value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Short preview of the conversation's latest message." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "last_message_at": { "description": "Commit only if the previous last_message_at value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "number", "description": "Most recent message time in Unix milliseconds." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "first_response_at": { "description": "Commit only if the previous first_response_at value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "number", "description": "First response time in Unix milliseconds, when a response has been recorded." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] } } } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_conversation_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "deleted": { "type": "string", "enum": [ "deleted", "already_deleted" ], "description": "deleted when this request removed the record; already_deleted when it was already absent." }, "cascaded": { "type": "array", "items": { "type": "string" }, "description": "IDs of dependent records deleted with this record." } }, "required": [ "deleted" ], "additionalProperties": false, "examples": [ { "deleted": "deleted" } ] } ``` --- # Update conversation Update a conversation by ID. Omitted fields stay unchanged; use unset to remove fields and expected to prevent overwriting a concurrent change. POST https://api.brigg.app/v1/operations/support.UpdateConversation ## Access & visibility Allow `support.UpdateConversation` on your API key. Resource read permissions: `core:Conversation`. Resource write permissions: `core:Conversation`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:Conversation` record. Find it with [support.ListConversations](/developers/reference/support/ListConversations). Use the record's top-level `id`, not a business field or account ID. | | `data` | [Conversation](#conversation-request-data) | No | The fields to set. | | `unset` | array of string | No | Keys of `data` to remove. Each item: `"inbox_ref"`, `"subject"`, `"contact_ref"`, `"company_ref"`, `"status"`, `"assignee_ref"`, `"channel"`, `"tags"`, `"snippet"`, `"last_message_at"`, `"first_response_at"`. | | `expected` | [object](#request-expected) | No | Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {"$absent":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource. | ### Conversation · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `inbox_ref` | string | No | ID of a `core:Inbox` record. Find it with [support.ListInboxes](/developers/reference/support/ListInboxes) and use the top-level `id`. This is not an account ID or a display name. | | `subject` | string | No | Conversation subject shown to the support team. | | `contact_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `company_ref` | string | No | ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name. | | `status` | string | No | Current case state. Resolved and closed are distinct stored states; use the value returned by the API. Allowed: `"new"`, `"open"`, `"pending"`, `"escalated"`, `"snoozed"`, `"resolved"`, `"closed"`. | | `assignee_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | ### request.expected | Field | Type | Required | Description | | --- | --- | --- | --- | | `inbox_ref` | string or [object](#request-expected-inbox-ref) | No | Commit only if the previous inbox_ref value matches; use $absent to require that this field is missing. | | `subject` | string or [object](#request-expected-subject) | No | Commit only if the previous subject value matches; use $absent to require that this field is missing. | | `contact_ref` | string or [object](#request-expected-contact-ref) | No | Commit only if the previous contact_ref value matches; use $absent to require that this field is missing. | | `company_ref` | string or [object](#request-expected-company-ref) | No | Commit only if the previous company_ref value matches; use $absent to require that this field is missing. | | `status` | string or [object](#request-expected-status) | No | Commit only if the previous status value matches; use $absent to require that this field is missing. | | `assignee_ref` | string or [object](#request-expected-assignee-ref) | No | Commit only if the previous assignee_ref value matches; use $absent to require that this field is missing. | | `channel` | string or [object](#request-expected-channel) | No | Commit only if the previous channel value matches; use $absent to require that this field is missing. | | `tags` | array of string or [object](#request-expected-tags) | No | Commit only if the previous tags value matches; use $absent to require that this field is missing. | | `snippet` | string or [object](#request-expected-snippet) | No | Commit only if the previous snippet value matches; use $absent to require that this field is missing. | | `last_message_at` | number or [object](#request-expected-last-message-at) | No | Commit only if the previous last_message_at value matches; use $absent to require that this field is missing. | | `first_response_at` | number or [object](#request-expected-first-response-at) | No | Commit only if the previous first_response_at value matches; use $absent to require that this field is missing. | ### request.expected.inbox_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.subject | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.contact_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.company_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.status | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.assignee_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.channel | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.tags | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.snippet | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.last_message_at | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.first_response_at | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ## Update without losing changes Send only the business fields you want to change in `data`; omitted fields stay unchanged. Use `unset` to remove an optional field. Setting a field to null is a different action and is allowed only when its schema permits null. Use `expected` for a conditional update: supply the values you last read for the fields whose concurrent changes would matter. `{"$absent": true}` expects a missing field. A conflict means you must read the record again and decide how to reconcile the change. Keep the same idempotency key when retrying the original action; use a new key for a revised action. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [ConversationRecord](#conversationrecord-response-item) | Yes | The requested record, including its metadata and data fields. | ### ConversationRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Conversation record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Conversation](#conversation-response-item-data) | Yes | The record's fields. | ### Conversation · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `inbox_ref` | string | No | ID of a `core:Inbox` record. Find it with [support.ListInboxes](/developers/reference/support/ListInboxes) and use the top-level `id`. This is not an account ID or a display name. | | `subject` | string | No | Conversation subject shown to the support team. | | `contact_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `company_ref` | string | No | ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name. | | `status` | string | No | Current case state. Resolved and closed are distinct stored states; use the value returned by the API. Allowed: `"new"`, `"open"`, `"pending"`, `"escalated"`, `"snoozed"`, `"resolved"`, `"closed"`. | | `assignee_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `channel` | string | No | Channel through which this conversation arrived. Allowed: `"email"`, `"web_chat"`, `"contact_form"`, `"sms"`, `"phone"`. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | | `snippet` | string | No | Short preview of the conversation's latest message. | | `last_message_at` | number | No | Most recent message time in Unix milliseconds. | | `first_response_at` | number | No | First response time in Unix milliseconds, when a response has been recorded. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `conflict` | A supplied expected value no longer matches. Read the record again before deciding whether to retry. | ## Next steps - [List conversations](/developers/reference/support/ListConversations) - [Get conversation](/developers/reference/support/GetConversation) - [Create conversation](/developers/reference/support/CreateConversation) - [Upsert conversation](/developers/reference/support/UpsertConversation) - [Delete conversation](/developers/reference/support/DeleteConversation) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.UpdateConversation' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_conversation_example", "data": { "status": "resolved" } }' ``` #### TypeScript ```typescript 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/support.UpdateConversation", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_conversation_example", "data": { "status": "resolved" } }), }); 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_conversation_example", "data": { "status": "resolved" } } request = Request( "https://api.brigg.app/v1/operations/support.UpdateConversation", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_conversation_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "inbox_ref": "e_inbox_support", "subject": "Help with onboarding", "contact_ref": "e_person_alex", "status": "resolved", "channel": "email", "snippet": "Can you help us import our contacts?", "last_message_at": 1791279900000 } } } ``` ### Update only if unchanged Use a value you actually read. A concurrent change refuses the write with 409 conflict. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.UpdateConversation' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_conversation_example", "data": { "status": "resolved" }, "expected": { "inbox_ref": "e_inbox_support" } }' ``` #### TypeScript ```typescript 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/support.UpdateConversation", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_conversation_example", "data": { "status": "resolved" }, "expected": { "inbox_ref": "e_inbox_support" } }), }); 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_conversation_example", "data": { "status": "resolved" }, "expected": { "inbox_ref": "e_inbox_support" } } request = Request( "https://api.brigg.app/v1/operations/support.UpdateConversation", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_conversation_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "inbox_ref": "e_inbox_support", "subject": "Help with onboarding", "contact_ref": "e_person_alex", "status": "resolved", "channel": "email", "snippet": "Can you help us import our contacts?", "last_message_at": 1791279900000 } } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:Conversation` record. Find it with [support.ListConversations](/developers/reference/support/ListConversations). Use the record's top-level `id`, not a business field or account ID." }, "data": { "type": "object", "properties": { "inbox_ref": { "type": "string", "description": "ID of a `core:Inbox` record. Find it with [support.ListInboxes](/developers/reference/support/ListInboxes) and use the top-level `id`. This is not an account ID or a display name." }, "subject": { "type": "string", "description": "Conversation subject shown to the support team." }, "contact_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "company_ref": { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." }, "status": { "type": "string", "enum": [ "new", "open", "pending", "escalated", "snoozed", "resolved", "closed" ], "description": "Current case state. Resolved and closed are distinct stored states; use the value returned by the API." }, "assignee_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." } }, "additionalProperties": false, "required": [], "description": "The fields to set.", "title": "Conversation" }, "unset": { "type": "array", "items": { "type": "string", "enum": [ "inbox_ref", "subject", "contact_ref", "company_ref", "status", "assignee_ref", "channel", "tags", "snippet", "last_message_at", "first_response_at" ] }, "description": "Keys of `data` to remove." }, "expected": { "type": "object", "description": "Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {\"$absent\":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource.", "additionalProperties": false, "properties": { "inbox_ref": { "description": "Commit only if the previous inbox_ref value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "ID of a `core:Inbox` record. Find it with [support.ListInboxes](/developers/reference/support/ListInboxes) and use the top-level `id`. This is not an account ID or a display name." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "subject": { "description": "Commit only if the previous subject value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Conversation subject shown to the support team." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "contact_ref": { "description": "Commit only if the previous contact_ref value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "company_ref": { "description": "Commit only if the previous company_ref value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "status": { "description": "Commit only if the previous status value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "enum": [ "new", "open", "pending", "escalated", "snoozed", "resolved", "closed" ], "description": "Current case state. Resolved and closed are distinct stored states; use the value returned by the API." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "assignee_ref": { "description": "Commit only if the previous assignee_ref value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "channel": { "description": "Commit only if the previous channel value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "enum": [ "email", "web_chat", "contact_form", "sms", "phone" ], "description": "Channel through which this conversation arrived." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "tags": { "description": "Commit only if the previous tags value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "snippet": { "description": "Commit only if the previous snippet value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Short preview of the conversation's latest message." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "last_message_at": { "description": "Commit only if the previous last_message_at value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "number", "description": "Most recent message time in Unix milliseconds." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "first_response_at": { "description": "Commit only if the previous first_response_at value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "number", "description": "First response time in Unix milliseconds, when a response has been recorded." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] } } } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_conversation_example", "data": { "status": "resolved" } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:Conversation record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "inbox_ref": { "type": "string", "description": "ID of a `core:Inbox` record. Find it with [support.ListInboxes](/developers/reference/support/ListInboxes) and use the top-level `id`. This is not an account ID or a display name." }, "subject": { "type": "string", "description": "Conversation subject shown to the support team." }, "contact_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "company_ref": { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." }, "status": { "type": "string", "enum": [ "new", "open", "pending", "escalated", "snoozed", "resolved", "closed" ], "description": "Current case state. Resolved and closed are distinct stored states; use the value returned by the API." }, "assignee_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "channel": { "type": "string", "enum": [ "email", "web_chat", "contact_form", "sms", "phone" ], "description": "Channel through which this conversation arrived." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, "snippet": { "type": "string", "description": "Short preview of the conversation's latest message." }, "last_message_at": { "type": "number", "description": "Most recent message time in Unix milliseconds." }, "first_response_at": { "type": "number", "description": "First response time in Unix milliseconds, when a response has been recorded." } }, "additionalProperties": false, "description": "The record's fields.", "title": "Conversation" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "ConversationRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_conversation_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "inbox_ref": "e_inbox_support", "subject": "Help with onboarding", "contact_ref": "e_person_alex", "status": "resolved", "channel": "email", "snippet": "Can you help us import our contacts?", "last_message_at": 1791279900000 } } } ] } ``` --- # Upsert conversation Create or update a conversation by a permanent external reference. Matching is exact within the workspace, resource type and ownership scope. Supplied fields replace their values; omitted fields stay unchanged. Deleted records are not recreated. POST https://api.brigg.app/v1/operations/support.UpsertConversation ## Access & visibility Allow `support.UpsertConversation` on your API key. Resource read permissions: `core:Conversation`. Resource write permissions: `core:Conversation`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `data` | [Conversation](#conversation-request-data) | Yes | The record's fields. | | `private` | boolean | No | Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance. | | `external_ref` | [object](#request-external-ref) | Yes | Permanent, case-sensitive source identity within this workspace, resource type and private/workspace scope. It is independent of API key rotation and retry receipt expiry. | ### Conversation · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `inbox_ref` | string | No | ID of a `core:Inbox` record. Find it with [support.ListInboxes](/developers/reference/support/ListInboxes) and use the top-level `id`. This is not an account ID or a display name. | | `subject` | string | No | Conversation subject shown to the support team. | | `contact_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `company_ref` | string | No | ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name. | | `status` | string | No | Current case state. Resolved and closed are distinct stored states; use the value returned by the API. Allowed: `"new"`, `"open"`, `"pending"`, `"escalated"`, `"snoozed"`, `"resolved"`, `"closed"`. | | `assignee_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | ### request.external_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `namespace` | string | Yes | A stable name for the source system, such as crm-production. At least 1 character. | | `id` | string | Yes | The record ID in that source system. At least 1 character. | ## Sync with a permanent external reference Choose a stable `external_ref.namespace` for your source system and put its record ID in `external_ref.id`. Matching is case-sensitive and scoped to this workspace, resource type and private/workspace ownership. The reference survives API key replacement and the 30-day retry receipt window. It does not match records by email or name. Send the required create fields each time. A missing reference creates a record; an existing reference updates only supplied fields and preserves everything else. `created` tells you which happened. Use the same idempotency key when retrying a lost response and a new key for a later source change. Concurrent calls cannot create duplicate records. A deleted or inaccessible match is refused; the operation does not restore it or make a replacement. Use the returned `item.id` with the regular update operation when you need `unset` or a conditional `expected` edit. Changing `private` chooses a different ownership scope; it does not transfer an existing record. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [ConversationRecord](#conversationrecord-response-item) | Yes | The requested record, including its metadata and data fields. | | `created` | boolean | Yes | True when this external reference created a record; false when it matched an existing record. | ### ConversationRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Conversation record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Conversation](#conversation-response-item-data) | Yes | The record's fields. | ### Conversation · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `inbox_ref` | string | No | ID of a `core:Inbox` record. Find it with [support.ListInboxes](/developers/reference/support/ListInboxes) and use the top-level `id`. This is not an account ID or a display name. | | `subject` | string | No | Conversation subject shown to the support team. | | `contact_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `company_ref` | string | No | ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name. | | `status` | string | No | Current case state. Resolved and closed are distinct stored states; use the value returned by the API. Allowed: `"new"`, `"open"`, `"pending"`, `"escalated"`, `"snoozed"`, `"resolved"`, `"closed"`. | | `assignee_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `channel` | string | No | Channel through which this conversation arrived. Allowed: `"email"`, `"web_chat"`, `"contact_form"`, `"sms"`, `"phone"`. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | | `snippet` | string | No | Short preview of the conversation's latest message. | | `last_message_at` | number | No | Most recent message time in Unix milliseconds. | | `first_response_at` | number | No | First response time in Unix milliseconds, when a response has been recorded. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List conversations](/developers/reference/support/ListConversations) - [Get conversation](/developers/reference/support/GetConversation) - [Create conversation](/developers/reference/support/CreateConversation) - [Update conversation](/developers/reference/support/UpdateConversation) - [Delete conversation](/developers/reference/support/DeleteConversation) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### First sync Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.UpsertConversation' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "inbox_ref": "e_inbox_support", "subject": "Help with onboarding", "contact_ref": "e_person_alex", "status": "open" } }' ``` #### TypeScript ```typescript 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/support.UpsertConversation", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "inbox_ref": "e_inbox_support", "subject": "Help with onboarding", "contact_ref": "e_person_alex", "status": "open" } }), }); 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 = { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "inbox_ref": "e_inbox_support", "subject": "Help with onboarding", "contact_ref": "e_person_alex", "status": "open" } } request = Request( "https://api.brigg.app/v1/operations/support.UpsertConversation", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_conversation_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "inbox_ref": "e_inbox_support", "subject": "Help with onboarding", "contact_ref": "e_person_alex", "status": "open", "channel": "email", "snippet": "Can you help us import our contacts?", "last_message_at": 1791279900000 } }, "created": true } ``` ### Later sync The same external reference returns the same record ID. Use a new idempotency key for a later source change. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.UpsertConversation' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "inbox_ref": "e_inbox_support", "subject": "Help with onboarding", "contact_ref": "e_person_alex", "status": "open" } }' ``` #### TypeScript ```typescript 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/support.UpsertConversation", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "inbox_ref": "e_inbox_support", "subject": "Help with onboarding", "contact_ref": "e_person_alex", "status": "open" } }), }); 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 = { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "inbox_ref": "e_inbox_support", "subject": "Help with onboarding", "contact_ref": "e_person_alex", "status": "open" } } request = Request( "https://api.brigg.app/v1/operations/support.UpsertConversation", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_conversation_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "inbox_ref": "e_inbox_support", "subject": "Help with onboarding", "contact_ref": "e_person_alex", "status": "open", "channel": "email", "snippet": "Can you help us import our contacts?", "last_message_at": 1791279900000 } }, "created": false } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "data": { "type": "object", "properties": { "inbox_ref": { "type": "string", "description": "ID of a `core:Inbox` record. Find it with [support.ListInboxes](/developers/reference/support/ListInboxes) and use the top-level `id`. This is not an account ID or a display name." }, "subject": { "type": "string", "description": "Conversation subject shown to the support team." }, "contact_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "company_ref": { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." }, "status": { "type": "string", "enum": [ "new", "open", "pending", "escalated", "snoozed", "resolved", "closed" ], "description": "Current case state. Resolved and closed are distinct stored states; use the value returned by the API." }, "assignee_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." } }, "additionalProperties": false, "description": "The record's fields.", "title": "Conversation" }, "private": { "type": "boolean", "description": "Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance." }, "external_ref": { "type": "object", "description": "Permanent, case-sensitive source identity within this workspace, resource type and private/workspace scope. It is independent of API key rotation and retry receipt expiry.", "properties": { "namespace": { "type": "string", "minLength": 1, "description": "A stable name for the source system, such as crm-production." }, "id": { "type": "string", "minLength": 1, "description": "The record ID in that source system." } }, "required": [ "namespace", "id" ], "additionalProperties": false } }, "required": [ "external_ref", "data" ], "additionalProperties": false, "examples": [ { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "inbox_ref": "e_inbox_support", "subject": "Help with onboarding", "contact_ref": "e_person_alex", "status": "open" } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:Conversation record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "inbox_ref": { "type": "string", "description": "ID of a `core:Inbox` record. Find it with [support.ListInboxes](/developers/reference/support/ListInboxes) and use the top-level `id`. This is not an account ID or a display name." }, "subject": { "type": "string", "description": "Conversation subject shown to the support team." }, "contact_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "company_ref": { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." }, "status": { "type": "string", "enum": [ "new", "open", "pending", "escalated", "snoozed", "resolved", "closed" ], "description": "Current case state. Resolved and closed are distinct stored states; use the value returned by the API." }, "assignee_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "channel": { "type": "string", "enum": [ "email", "web_chat", "contact_form", "sms", "phone" ], "description": "Channel through which this conversation arrived." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, "snippet": { "type": "string", "description": "Short preview of the conversation's latest message." }, "last_message_at": { "type": "number", "description": "Most recent message time in Unix milliseconds." }, "first_response_at": { "type": "number", "description": "First response time in Unix milliseconds, when a response has been recorded." } }, "additionalProperties": false, "description": "The record's fields.", "title": "Conversation" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "ConversationRecord" }, "created": { "type": "boolean", "description": "True when this external reference created a record; false when it matched an existing record." } }, "required": [ "item", "created" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_conversation_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "inbox_ref": "e_inbox_support", "subject": "Help with onboarding", "contact_ref": "e_person_alex", "status": "open", "channel": "email", "snippet": "Can you help us import our contacts?", "last_message_at": 1791279900000 } }, "created": true } ] } ``` --- # Get inbox Read an inbox by ID. Returns item: null when no visible record matches. POST https://api.brigg.app/v1/operations/support.GetInbox ## Access & visibility Allow `support.GetInbox` on your API key. Resource read permissions: `core:Inbox`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:Inbox` record. Find it with [support.ListInboxes](/developers/reference/support/ListInboxes). Use the record's top-level `id`, not a business field or account ID. | ## Response Returns **200 OK** with a JSON body. `item: null` means there is no matching record visible to this caller. It does not reveal whether an inaccessible record exists. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [InboxRecord](#inboxrecord-response-item) or null | Yes | null when no such record | ### InboxRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Inbox record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Inbox](#inbox-response-item-data) | Yes | The record's fields. | ### Inbox · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Team inbox display name. | | `slug` | string | No | Stable URL segment identifying this item. Pattern: `^[a-z][a-z0-9-]*$`. | | `description` | string | No | Purpose and scope of the team inbox. | | `purpose` | string | No | Whether the inbox handles customer support or reception. Allowed: `"support"`, `"reception"`. | | `accent` | string | No | Display color token; it does not change routing or access. Allowed: `"green"`, `"blue"`, `"amber"`, `"violet"`, `"neutral"`. | | `default_assignee_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `auto_assign_on_reply` | boolean | No | Whether the first member reply assigns an unassigned conversation to that member. | | `agent_first_email` | boolean | No | Whether the inbox agent takes the first turn on incoming email before escalating work to a person. | | `agent_first_web_chat` | boolean | No | Whether the inbox agent takes the first turn on incoming web chat before escalating work to a person. | | `round_robin` | boolean | No | Saved round-robin preference. This setting does not currently cause automatic assignment. | | `playbook_md` | string | No | Shared answering and escalation instructions in Markdown. | | `voice_playbook_md` | string | No | Additional instructions for spoken phone conversations; the shared playbook still applies. | | `signature_md` | string | No | Markdown footer appended to outgoing replies from this inbox. | | `web_chat_welcome` | string | No | Welcome message shown to web chat visitors. Empty or absent uses the localized default. | | `doc_folders` | array of [object](#response-item-data-doc-folders) | No | Document folders made available as reference material to this inbox. | ### response.item.data.doc_folders[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `scope` | string | No | Document collection scope containing the folder. | | `path` | string | No | Path to the folder within the document collection. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [List inboxes](/developers/reference/support/ListInboxes) - [Update inbox](/developers/reference/support/UpdateInbox) - [Delete inbox](/developers/reference/support/DeleteInbox) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.GetInbox' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "e_inbox_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/support.GetInbox", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "id": "e_inbox_example" }), }); 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 payload = { "id": "e_inbox_example" } request = Request( "https://api.brigg.app/v1/operations/support.GetInbox", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "item": { "id": "e_inbox_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "Customer support", "slug": "support", "purpose": "support", "auto_assign_on_reply": true, "playbook_md": "Answer product questions. Escalate billing disputes to a person." } } } ``` ### No visible record A missing or inaccessible record returns item: null. Do not treat this as proof that a record exists for another member. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.GetInbox' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "e_inbox_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/support.GetInbox", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "id": "e_inbox_example" }), }); 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 payload = { "id": "e_inbox_example" } request = Request( "https://api.brigg.app/v1/operations/support.GetInbox", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "item": null } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:Inbox` record. Find it with [support.ListInboxes](/developers/reference/support/ListInboxes). Use the record's top-level `id`, not a business field or account ID." } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_inbox_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": [ "object", "null" ], "properties": { "id": { "type": "string", "description": "Stable core:Inbox record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "name": { "type": "string", "description": "Team inbox display name." }, "slug": { "type": "string", "pattern": "^[a-z][a-z0-9-]*$", "description": "Stable URL segment identifying this item." }, "description": { "type": "string", "description": "Purpose and scope of the team inbox." }, "purpose": { "type": "string", "enum": [ "support", "reception" ], "description": "Whether the inbox handles customer support or reception." }, "accent": { "type": "string", "enum": [ "green", "blue", "amber", "violet", "neutral" ], "description": "Display color token; it does not change routing or access." }, "default_assignee_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "auto_assign_on_reply": { "type": "boolean", "description": "Whether the first member reply assigns an unassigned conversation to that member." }, "agent_first_email": { "type": "boolean", "description": "Whether the inbox agent takes the first turn on incoming email before escalating work to a person." }, "agent_first_web_chat": { "type": "boolean", "description": "Whether the inbox agent takes the first turn on incoming web chat before escalating work to a person." }, "round_robin": { "type": "boolean", "description": "Saved round-robin preference. This setting does not currently cause automatic assignment." }, "playbook_md": { "type": "string", "description": "Shared answering and escalation instructions in Markdown." }, "voice_playbook_md": { "type": "string", "description": "Additional instructions for spoken phone conversations; the shared playbook still applies." }, "signature_md": { "type": "string", "description": "Markdown footer appended to outgoing replies from this inbox." }, "web_chat_welcome": { "type": "string", "description": "Welcome message shown to web chat visitors. Empty or absent uses the localized default." }, "doc_folders": { "type": "array", "items": { "type": "object", "properties": { "scope": { "type": "string", "description": "Document collection scope containing the folder." }, "path": { "type": "string", "description": "Path to the folder within the document collection." } }, "additionalProperties": false }, "description": "Document folders made available as reference material to this inbox." } }, "required": [ "name" ], "additionalProperties": false, "description": "The record's fields.", "title": "Inbox" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "null when no such record", "title": "InboxRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_inbox_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "Customer support", "slug": "support", "purpose": "support", "auto_assign_on_reply": true, "playbook_md": "Answer product questions. Escalate billing disputes to a person." } } } ] } ``` --- # List inbox channels List the forwarding email addresses for the workspace's support inboxes. POST https://api.brigg.app/v1/operations/support.ListInboxChannels ## Access & visibility Allow `support.ListInboxChannels` on your API key. Resource read permissions: `core:Inbox`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/permissions) ## Request No parameters. Send an empty JSON object (`{}`). ## Connect your public support address Use forward_address exactly as returned as the destination in your email provider’s forwarding rule. It is Brigg’s delivery address, not the address customers should necessarily use or the additional Reply-To address. Do not derive it from the inbox slug. After forwarding is configured, [add the public support address](/developers/reference/support/AddInboxSupportAddress). That sends a verification email which must return through this inbox before the address can be used as Reply-To. Retain this row’s id as inbox_id for the support-address operations. Results are listed in inbox creation order and have no cursor. ## Response Returns **200 OK** with a JSON body. This operation has no continuation cursor. An empty `items` array means no matching visible results were returned. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [Support inbox](#support-inbox-response-items) | Yes | Support inboxes and their configured communication channels. This operation has no cursor pagination. | ### Support inbox · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Inbox record ID used by support-address and phone configuration operations. | | `slug` | string | Yes | Inbox routing label. Use the complete returned forward_address rather than constructing an email address or URL from this value. | | `name` | string | Yes | Display name of the team's support inbox. | | `forward_address` | string | Yes | Exact forwarding destination generated by Brigg for this inbox. Configure your email provider to forward the public support mailbox to this address. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | | 409 | `org_not_provisioned` | Finish workspace inbox setup in Brigg before reading forwarding destinations. | ## Next steps - [Add inbox support address](/developers/reference/support/AddInboxSupportAddress) - [List inbox support addresses](/developers/reference/support/ListInboxSupportAddresses) - [List inboxes](/developers/reference/support/ListInboxes) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Find the forwarding destination Forward your public help@example.com mailbox to the returned address, then verify it. This destination is fictional. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.ListInboxChannels' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{}' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/support.ListInboxChannels", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/support.ListInboxChannels", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_inbox_support", "slug": "support", "name": "Customer support", "forward_address": "in.fictional.support@inbound.example.com" } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": {}, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Inbox record ID used by support-address and phone configuration operations.", "examples": [ "inbox_support" ] }, "slug": { "type": "string", "description": "Inbox routing label. Use the complete returned forward_address rather than constructing an email address or URL from this value.", "examples": [ "support" ] }, "name": { "type": "string", "description": "Display name of the team's support inbox.", "examples": [ "Customer support" ] }, "forward_address": { "type": "string", "description": "Exact forwarding destination generated by Brigg for this inbox. Configure your email provider to forward the public support mailbox to this address.", "examples": [ "support@example.com" ] } }, "required": [ "id", "slug", "name", "forward_address" ], "additionalProperties": false, "title": "Support inbox" }, "description": "Support inboxes and their configured communication channels. This operation has no cursor pagination." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "id": "e_inbox_support", "slug": "support", "name": "Customer support", "forward_address": "in.fictional.support@inbound.example.com" } ] } ] } ``` --- # List inboxes List inboxes visible to the credential, with filtering, sorting and cursor pagination. POST https://api.brigg.app/v1/operations/support.ListInboxes ## Access & visibility Allow `support.ListInboxes` on your API key. Resource read permissions: `core:Inbox`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `filters` | array of [object](#request-filters) | No | Conditions the row must ALL satisfy. | | `sort` | [object](#request-sort) | No | Sort order for the results. Defaults to updated_at descending, with id as a tie-breaker. | | `limit` | integer | No | Maximum number of results to return in this page. Continue with next_cursor when returned. Default: `100`. Minimum: 1. | | `cursor` | string | No | The `next_cursor` of the previous page. | ### request.filters[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | `data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private. Allowed: `"id"`, `"created_at"`, `"updated_at"`, `"created_by"`, `"private"`, `"data.name"`, `"data.slug"`, `"data.description"`, `"data.purpose"`, `"data.accent"`, `"data.default_assignee_ref"`, `"data.auto_assign_on_reply"`, `"data.agent_first_email"`, `"data.agent_first_web_chat"`, `"data.round_robin"`, `"data.playbook_md"`, `"data.voice_playbook_md"`, `"data.signature_md"`, `"data.web_chat_welcome"`, `"data.doc_folders"`. | | `op` | string | Yes | Comparison operator. Use in with an array, or omit value for is_empty and is_not_empty. Allowed: `"eq"`, `"neq"`, `"contains"`, `"starts_with"`, `"gt"`, `"gte"`, `"lt"`, `"lte"`, `"in"`, `"has"`, `"is_empty"`, `"is_not_empty"`. | | `value` | JSON value | No | The comparison value; an array for `in`; omitted for is_empty / is_not_empty. | ### request.sort | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | `data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private. Allowed: `"id"`, `"created_at"`, `"updated_at"`, `"created_by"`, `"private"`, `"data.name"`, `"data.slug"`, `"data.description"`, `"data.purpose"`, `"data.accent"`, `"data.default_assignee_ref"`, `"data.auto_assign_on_reply"`, `"data.agent_first_email"`, `"data.agent_first_web_chat"`, `"data.round_robin"`, `"data.playbook_md"`, `"data.voice_playbook_md"`, `"data.signature_md"`, `"data.web_chat_welcome"`, `"data.doc_folders"`. | | `direction` | string | No | Sort direction: asc for ascending or desc for descending. Allowed: `"asc"`, `"desc"`. | ## Filtering and sorting All conditions are combined with **AND**. Address business fields as `data.`, and record metadata as `id`, `created_at`, `updated_at`, `created_by` or `private`. A field path names one field; it does not traverse nested objects. | Operator | Meaning | Value | | --- | --- | --- | | `eq` | Equal to a scalar | String, number, boolean or null | | `neq` | Not equal; missing values also match | String, number, boolean or null | | `contains` | Case-insensitive text contains | String; % and _ are literal characters | | `starts_with` | Case-insensitive text prefix | String | | `gt`, `gte` | Greater than / at least | Number or string appropriate to the field | | `lt`, `lte` | Less than / at most | Number or string appropriate to the field | | `in` | Equal to any supplied scalar | Nonempty array of strings, numbers, booleans or null | | `has` | Array contains a string | One string; does not match properties inside array objects | | `is_empty` | Missing, null, empty string or empty array | Omit value | | `is_not_empty` | Has a nonempty value | Omit value | Match the stored field's type. Numeric business timestamps take Unix milliseconds; date-only business fields take `YYYY-MM-DD`. The record metadata fields `created_at` and `updated_at` also accept ISO timestamps for ordered comparisons. Sorting defaults to `updated_at` descending. If you supply `sort.field` without `sort.direction`, direction is `desc`. The record ID breaks ties; missing values sort last. ## Response Returns **200 OK** with a JSON body. An empty `items` array means this page contains no matching visible results. Follow `next_cursor` when present. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [InboxRecord](#inboxrecord-response-items) | Yes | Records visible under the credential's grants and the selected data scope, matching the requested filters. Pass next_cursor as cursor to continue when a next cursor is returned. | | `next_cursor` | string | No | Pass this value as cursor to continue with the same filters, sort and credential. Omitted when there are no more results. | ### InboxRecord · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Inbox record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Inbox](#inbox-response-items-data) | Yes | The record's fields. | ### Inbox · response.items[].data | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Team inbox display name. | | `slug` | string | No | Stable URL segment identifying this item. Pattern: `^[a-z][a-z0-9-]*$`. | | `description` | string | No | Purpose and scope of the team inbox. | | `purpose` | string | No | Whether the inbox handles customer support or reception. Allowed: `"support"`, `"reception"`. | | `accent` | string | No | Display color token; it does not change routing or access. Allowed: `"green"`, `"blue"`, `"amber"`, `"violet"`, `"neutral"`. | | `default_assignee_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `auto_assign_on_reply` | boolean | No | Whether the first member reply assigns an unassigned conversation to that member. | | `agent_first_email` | boolean | No | Whether the inbox agent takes the first turn on incoming email before escalating work to a person. | | `agent_first_web_chat` | boolean | No | Whether the inbox agent takes the first turn on incoming web chat before escalating work to a person. | | `round_robin` | boolean | No | Saved round-robin preference. This setting does not currently cause automatic assignment. | | `playbook_md` | string | No | Shared answering and escalation instructions in Markdown. | | `voice_playbook_md` | string | No | Additional instructions for spoken phone conversations; the shared playbook still applies. | | `signature_md` | string | No | Markdown footer appended to outgoing replies from this inbox. | | `web_chat_welcome` | string | No | Welcome message shown to web chat visitors. Empty or absent uses the localized default. | | `doc_folders` | array of [object](#response-items-data-doc-folders) | No | Document folders made available as reference material to this inbox. | ### response.items[].data.doc_folders[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `scope` | string | No | Document collection scope containing the folder. | | `path` | string | No | Path to the folder within the document collection. | ## Pagination Pass `next_cursor` from the response as `cursor` on the next request. Keep the same filters, sort and acting identity. Stop when `next_cursor` is absent; do not infer completion from the number of items. The default page size is **100**; `limit` must be a positive integer. **Pagination is a live view, not a snapshot.** Changes between pages can move records across page boundaries. Upsert by record ID rather than appending blindly. For recurring synchronization, use an overlapping update window and deduplicate records. Periodically reconcile IDs to detect deletions. [Resource webhooks](/developers/webhooks) can supplement synchronization for eligible workspace-shared records only: they do not export private or project-scoped records. Personal data still needs polling and reconciliation. ```typescript const query = { "limit": 10 }; let cursor; do { const response = await fetch("https://api.brigg.app/v1/operations/support.ListInboxes", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ ...query, ...(cursor ? { cursor } : {}) }), }); const page = await response.json(); if (!response.ok) throw new Error(`${response.status}: ${page.message}`); for (const item of page.items) { console.log(item); // Process or upsert each result. } cursor = page.next_cursor; } while (cursor); ``` ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | | 400 | `cursor_invalid` | Restart pagination with no cursor. | | 400 | `cursor_mismatch` | Use the cursor with the original filters, sort order and credential. | ## Next steps - [Get inbox](/developers/reference/support/GetInbox) - [Update inbox](/developers/reference/support/UpdateInbox) - [Delete inbox](/developers/reference/support/DeleteInbox) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### First page Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.ListInboxes' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "limit": 10 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/support.ListInboxes", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "limit": 10 }), }); 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 payload = { "limit": 10 } request = Request( "https://api.brigg.app/v1/operations/support.ListInboxes", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_inbox_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "Customer support", "slug": "support", "purpose": "support", "auto_assign_on_reply": true, "playbook_md": "Answer product questions. Escalate billing disputes to a person." } } ] } ``` ### Support inboxes Reception and customer support have different purposes. This filter selects customer support inboxes. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.ListInboxes' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "limit": 50, "filters": [ { "field": "data.purpose", "op": "eq", "value": "support" } ] }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/support.ListInboxes", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "limit": 50, "filters": [ { "field": "data.purpose", "op": "eq", "value": "support" } ] }), }); 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 payload = { "limit": 50, "filters": [ { "field": "data.purpose", "op": "eq", "value": "support" } ] } request = Request( "https://api.brigg.app/v1/operations/support.ListInboxes", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_inbox_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "Customer support", "slug": "support", "purpose": "support", "auto_assign_on_reply": true, "playbook_md": "Answer product questions. Escalate billing disputes to a person." } } ] } ``` ### Records updated since a checkpoint 6 October 2026 at 00:00 UTC. Use an overlap window and upsert by ID when synchronizing. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.ListInboxes' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/support.ListInboxes", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 }), }); 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 payload = { "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 } request = Request( "https://api.brigg.app/v1/operations/support.ListInboxes", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_inbox_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "Customer support", "slug": "support", "purpose": "support", "auto_assign_on_reply": true, "playbook_md": "Answer product questions. Escalate billing disputes to a person." } } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "filters": { "type": "array", "items": { "type": "object", "properties": { "field": { "type": "string", "description": "`data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private.", "enum": [ "id", "created_at", "updated_at", "created_by", "private", "data.name", "data.slug", "data.description", "data.purpose", "data.accent", "data.default_assignee_ref", "data.auto_assign_on_reply", "data.agent_first_email", "data.agent_first_web_chat", "data.round_robin", "data.playbook_md", "data.voice_playbook_md", "data.signature_md", "data.web_chat_welcome", "data.doc_folders" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "contains", "starts_with", "gt", "gte", "lt", "lte", "in", "has", "is_empty", "is_not_empty" ], "description": "Comparison operator. Use in with an array, or omit value for is_empty and is_not_empty." }, "value": { "description": "The comparison value; an array for `in`; omitted for is_empty / is_not_empty." } }, "required": [ "field", "op" ], "additionalProperties": false }, "description": "Conditions the row must ALL satisfy." }, "sort": { "type": "object", "properties": { "field": { "type": "string", "description": "`data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private.", "enum": [ "id", "created_at", "updated_at", "created_by", "private", "data.name", "data.slug", "data.description", "data.purpose", "data.accent", "data.default_assignee_ref", "data.auto_assign_on_reply", "data.agent_first_email", "data.agent_first_web_chat", "data.round_robin", "data.playbook_md", "data.voice_playbook_md", "data.signature_md", "data.web_chat_welcome", "data.doc_folders" ] }, "direction": { "type": "string", "enum": [ "asc", "desc" ], "description": "Sort direction: asc for ascending or desc for descending." } }, "required": [ "field" ], "additionalProperties": false, "description": "Sort order for the results. Defaults to updated_at descending, with id as a tie-breaker." }, "limit": { "type": "integer", "minimum": 1, "default": 100, "description": "Maximum number of results to return in this page. Continue with next_cursor when returned." }, "cursor": { "type": "string", "description": "The `next_cursor` of the previous page." } }, "additionalProperties": false, "examples": [ { "limit": 10 } ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:Inbox record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "name": { "type": "string", "description": "Team inbox display name." }, "slug": { "type": "string", "pattern": "^[a-z][a-z0-9-]*$", "description": "Stable URL segment identifying this item." }, "description": { "type": "string", "description": "Purpose and scope of the team inbox." }, "purpose": { "type": "string", "enum": [ "support", "reception" ], "description": "Whether the inbox handles customer support or reception." }, "accent": { "type": "string", "enum": [ "green", "blue", "amber", "violet", "neutral" ], "description": "Display color token; it does not change routing or access." }, "default_assignee_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "auto_assign_on_reply": { "type": "boolean", "description": "Whether the first member reply assigns an unassigned conversation to that member." }, "agent_first_email": { "type": "boolean", "description": "Whether the inbox agent takes the first turn on incoming email before escalating work to a person." }, "agent_first_web_chat": { "type": "boolean", "description": "Whether the inbox agent takes the first turn on incoming web chat before escalating work to a person." }, "round_robin": { "type": "boolean", "description": "Saved round-robin preference. This setting does not currently cause automatic assignment." }, "playbook_md": { "type": "string", "description": "Shared answering and escalation instructions in Markdown." }, "voice_playbook_md": { "type": "string", "description": "Additional instructions for spoken phone conversations; the shared playbook still applies." }, "signature_md": { "type": "string", "description": "Markdown footer appended to outgoing replies from this inbox." }, "web_chat_welcome": { "type": "string", "description": "Welcome message shown to web chat visitors. Empty or absent uses the localized default." }, "doc_folders": { "type": "array", "items": { "type": "object", "properties": { "scope": { "type": "string", "description": "Document collection scope containing the folder." }, "path": { "type": "string", "description": "Path to the folder within the document collection." } }, "additionalProperties": false }, "description": "Document folders made available as reference material to this inbox." } }, "required": [ "name" ], "additionalProperties": false, "description": "The record's fields.", "title": "Inbox" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "title": "InboxRecord" }, "description": "Records visible under the credential's grants and the selected data scope, matching the requested filters. Pass next_cursor as cursor to continue when a next cursor is returned." }, "next_cursor": { "type": "string", "description": "Pass this value as cursor to continue with the same filters, sort and credential. Omitted when there are no more results." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "id": "e_inbox_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "Customer support", "slug": "support", "purpose": "support", "auto_assign_on_reply": true, "playbook_md": "Answer product questions. Escalate billing disputes to a person." } } ] } ] } ``` --- # List inbox support addresses List pending and verified additional support addresses for an inbox. Verification confirms forwarding; it does not make the address an authenticated sender. POST https://api.brigg.app/v1/operations/support.ListInboxSupportAddresses ## Access & visibility Allow `support.ListInboxSupportAddresses` on your API key. Resource read permissions: `core:Inbox`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `inbox_id` | string | Yes | Use the support inbox record's top-level id, not its slug or forwarding address. [support.ListInboxes](/developers/reference/support/ListInboxes). At least 1 character. | ## Verify forwarding before using a support address Get the inbox_id and forwarding address from [List inbox channels](/developers/reference/support/ListInboxChannels). Configure your mail provider to forward the public support address into that inbox, then [add the address](/developers/reference/support/AddInboxSupportAddress). Adding it sends a verification email; the address becomes verified only when that email is forwarded back into the correct Brigg inbox. List support addresses to check verified_at. A test=sent response only confirms a send attempt; it is not verification. Only the newest test can verify, and it expires after 24 hours. Fix forwarding before requesting another test. Verification permits that address to be used as Reply-To for its conversations; it does not change the authenticated sender. Removing the address withdraws its verified Reply-To use. It does not remove your mail provider's forwarding rule or delete the inbox and its conversations. Change provider forwarding separately when retiring the address. ## Response Returns **200 OK** with a JSON body. This operation has no continuation cursor. An empty `items` array means no matching visible results were returned. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [Support address](#support-address-response-items) | Yes | Additional support addresses configured for the selected inbox. This operation has no cursor pagination. | ### Support address · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Additional address id from ListInboxSupportAddresses.items for this same inbox_id. It is not the email address, inbox ID, or a verification token. | | `address` | string | Yes | Normalized additional public support email address, distinct from Brigg's generated inbox-forwarding address. | | `created_at` | number | Yes | Unix millisecond timestamp when this address was added. | | `verified_at` | number or null | Yes | Unix millisecond time a valid test returned through this inbox, or null while unverified. | | `test_sent_at` | number or null | Yes | Unix millisecond time the newest test was sent, or null if no test has been sent. This does not prove verification. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [Add inbox support address](/developers/reference/support/AddInboxSupportAddress) - [Resend inbox support address test](/developers/reference/support/ResendInboxSupportAddressTest) - [Remove inbox support address](/developers/reference/support/RemoveInboxSupportAddress) - [List inbox channels](/developers/reference/support/ListInboxChannels) - [List inboxes](/developers/reference/support/ListInboxes) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### One verified and one pending address Only the first address has completed the return-mail check. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.ListInboxSupportAddresses' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "inbox_id": "e_inbox_support" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/support.ListInboxSupportAddresses", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "inbox_id": "e_inbox_support" }), }); 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 payload = { "inbox_id": "e_inbox_support" } request = Request( "https://api.brigg.app/v1/operations/support.ListInboxSupportAddresses", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "isa_help", "address": "help@example.com", "created_at": 1794301200000, "verified_at": 1794301260000, "test_sent_at": 1794301200000 }, { "id": "isa_billing", "address": "billing@example.com", "created_at": 1794301200000, "verified_at": null, "test_sent_at": 1794301200000 } ] } ``` ### No additional addresses The inbox still has its normal Brigg forwarding address. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.ListInboxSupportAddresses' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "inbox_id": "e_inbox_support" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/support.ListInboxSupportAddresses", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "inbox_id": "e_inbox_support" }), }); 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 payload = { "inbox_id": "e_inbox_support" } request = Request( "https://api.brigg.app/v1/operations/support.ListInboxSupportAddresses", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "inbox_id": { "type": "string", "minLength": 1, "description": "Use the support inbox record's top-level id, not its slug or forwarding address. [support.ListInboxes](/developers/reference/support/ListInboxes)." } }, "required": [ "inbox_id" ], "additionalProperties": false, "examples": [ { "inbox_id": "e_inbox_support" } ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Additional address id from ListInboxSupportAddresses.items for this same inbox_id. It is not the email address, inbox ID, or a verification token.", "examples": [ "address_support" ] }, "address": { "type": "string", "description": "Normalized additional public support email address, distinct from Brigg's generated inbox-forwarding address.", "examples": [ "help@example.com" ] }, "created_at": { "type": "number", "description": "Unix millisecond timestamp when this address was added.", "examples": [ 1794301200000 ] }, "verified_at": { "type": [ "number", "null" ], "description": "Unix millisecond time a valid test returned through this inbox, or null while unverified.", "examples": [ 1794301260000 ] }, "test_sent_at": { "type": [ "number", "null" ], "description": "Unix millisecond time the newest test was sent, or null if no test has been sent. This does not prove verification.", "examples": [ 1794301200000 ] } }, "required": [ "id", "address", "created_at", "verified_at", "test_sent_at" ], "additionalProperties": false, "title": "Support address" }, "description": "Additional support addresses configured for the selected inbox. This operation has no cursor pagination." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "id": "isa_help", "address": "help@example.com", "created_at": 1794301200000, "verified_at": 1794301260000, "test_sent_at": 1794301200000 }, { "id": "isa_billing", "address": "billing@example.com", "created_at": 1794301200000, "verified_at": null, "test_sent_at": 1794301200000 } ] } ] } ``` --- # Create inbox Create a team inbox with its forwarding email address and web chat channel. Returns the inbox ID, URL slug and forwarding address. POST https://api.brigg.app/v1/operations/support.CreateInbox ## Access & visibility Allow `support.CreateInbox` on your API key. Resource write permissions: `core:Inbox`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `name` | string | Yes | Team inbox name, for example Customer support or Billing. Brigg derives its slug and forwarding address from this name. At least 1 character. At most 80 characters. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Unique identifier. Use the value returned by a create or list operation. | | `slug` | string | Yes | Stable URL segment identifying this item. | | `name` | string | Yes | Display name. | | `forward_address` | string or null | Yes | The inbox's inbound address; null until the org holds a chat token. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List inboxes](/developers/reference/support/ListInboxes) - [List inbox channels](/developers/reference/support/ListInboxChannels) - [Update inbox](/developers/reference/support/UpdateInbox) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.CreateInbox' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "name": "Customer support" }' ``` #### TypeScript ```typescript 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/support.CreateInbox", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "name": "Customer support" }), }); 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 = { "name": "Customer support" } request = Request( "https://api.brigg.app/v1/operations/support.CreateInbox", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "id": "e_example", "slug": "support", "name": "Customer support", "forward_address": "support@example.com" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 80, "description": "Team inbox name, for example Customer support or Billing. Brigg derives its slug and forwarding address from this name." } }, "required": [ "name" ], "additionalProperties": false, "examples": [ { "name": "Customer support" } ] } ``` ```json-schema-response { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier. Use the value returned by a create or list operation." }, "slug": { "type": "string", "description": "Stable URL segment identifying this item." }, "name": { "type": "string", "description": "Display name." }, "forward_address": { "type": [ "string", "null" ], "description": "The inbox's inbound address; null until the org holds a chat token." } }, "required": [ "id", "slug", "name", "forward_address" ], "additionalProperties": false, "examples": [ { "id": "e_example", "slug": "support", "name": "Customer support", "forward_address": "support@example.com" } ] } ``` --- # Delete inbox Delete an inbox by ID. Repeating a deletion returns already_deleted. POST https://api.brigg.app/v1/operations/support.DeleteInbox ## Access & visibility Allow `support.DeleteInbox` on your API key. Resource read permissions: `core:Inbox`. Resource write permissions: `core:Inbox`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:Inbox` record. Find it with [support.ListInboxes](/developers/reference/support/ListInboxes). Use the record's top-level `id`, not a business field or account ID. | | `expected` | [object](#request-expected) | No | Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {"$absent":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource. | ### request.expected | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string or [object](#request-expected-name) | No | Commit only if the previous name value matches; use $absent to require that this field is missing. | | `slug` | string or [object](#request-expected-slug) | No | Commit only if the previous slug value matches; use $absent to require that this field is missing. | | `description` | string or [object](#request-expected-description) | No | Commit only if the previous description value matches; use $absent to require that this field is missing. | | `purpose` | string or [object](#request-expected-purpose) | No | Commit only if the previous purpose value matches; use $absent to require that this field is missing. | | `accent` | string or [object](#request-expected-accent) | No | Commit only if the previous accent value matches; use $absent to require that this field is missing. | | `default_assignee_ref` | string or [object](#request-expected-default-assignee-ref) | No | Commit only if the previous default_assignee_ref value matches; use $absent to require that this field is missing. | | `auto_assign_on_reply` | boolean or [object](#request-expected-auto-assign-on-reply) | No | Commit only if the previous auto_assign_on_reply value matches; use $absent to require that this field is missing. | | `agent_first_email` | boolean or [object](#request-expected-agent-first-email) | No | Commit only if the previous agent_first_email value matches; use $absent to require that this field is missing. | | `agent_first_web_chat` | boolean or [object](#request-expected-agent-first-web-chat) | No | Commit only if the previous agent_first_web_chat value matches; use $absent to require that this field is missing. | | `round_robin` | boolean or [object](#request-expected-round-robin) | No | Commit only if the previous round_robin value matches; use $absent to require that this field is missing. | | `playbook_md` | string or [object](#request-expected-playbook-md) | No | Commit only if the previous playbook_md value matches; use $absent to require that this field is missing. | | `voice_playbook_md` | string or [object](#request-expected-voice-playbook-md) | No | Commit only if the previous voice_playbook_md value matches; use $absent to require that this field is missing. | | `signature_md` | string or [object](#request-expected-signature-md) | No | Commit only if the previous signature_md value matches; use $absent to require that this field is missing. | | `web_chat_welcome` | string or [object](#request-expected-web-chat-welcome) | No | Commit only if the previous web_chat_welcome value matches; use $absent to require that this field is missing. | | `doc_folders` | array of [object](#request-expected-doc-folders) or [object](#request-expected-doc-folders) | No | Commit only if the previous doc_folders value matches; use $absent to require that this field is missing. | ### request.expected.name | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.slug | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.description | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.purpose | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.accent | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.default_assignee_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.auto_assign_on_reply | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.agent_first_email | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.agent_first_web_chat | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.round_robin | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.playbook_md | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.voice_playbook_md | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.signature_md | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.web_chat_welcome | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.doc_folders | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.doc_folders[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `scope` | string | No | Document collection scope containing the folder. | | `path` | string | No | Path to the folder within the document collection. | ## Deletion and retries A successful response reports whether this call removed the record or it was already absent. Check `cascaded` for dependent record IDs returned by the operation. Retrying the same action uses the original idempotency key. A successful deletion is not an archive you can restore through this operation. To avoid deleting a record someone has changed, read it first and put the relevant prior business values in `expected`. Keys are relative to `data`, not prefixed with `data.`. Use {"$absent": true} to require a missing field. A mismatch returns 409 conflict; read again and decide whether deletion is still appropriate. A revised action needs a new idempotency key. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `deleted` | string | Yes | deleted when this request removed the record; already_deleted when it was already absent. Allowed: `"deleted"`, `"already_deleted"`. | | `cascaded` | array of string | No | IDs of dependent records deleted with this 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `conflict` | A supplied expected value no longer matches. Read the record again before deciding whether to retry. | ## Next steps - [List inboxes](/developers/reference/support/ListInboxes) - [Get inbox](/developers/reference/support/GetInbox) - [Update inbox](/developers/reference/support/UpdateInbox) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.DeleteInbox' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_inbox_example" }' ``` #### TypeScript ```typescript 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/support.DeleteInbox", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_inbox_example" }), }); 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_inbox_example" } request = Request( "https://api.brigg.app/v1/operations/support.DeleteInbox", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "deleted": "deleted" } ``` ### Delete only if unchanged Use a value you actually read. A concurrent change refuses the write with 409 conflict. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.DeleteInbox' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_inbox_example", "expected": { "name": "Customer support" } }' ``` #### TypeScript ```typescript 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/support.DeleteInbox", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_inbox_example", "expected": { "name": "Customer support" } }), }); 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_inbox_example", "expected": { "name": "Customer support" } } request = Request( "https://api.brigg.app/v1/operations/support.DeleteInbox", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "deleted": "deleted" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:Inbox` record. Find it with [support.ListInboxes](/developers/reference/support/ListInboxes). Use the record's top-level `id`, not a business field or account ID." }, "expected": { "type": "object", "description": "Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {\"$absent\":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource.", "additionalProperties": false, "properties": { "name": { "description": "Commit only if the previous name value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Team inbox display name." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "slug": { "description": "Commit only if the previous slug value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "pattern": "^[a-z][a-z0-9-]*$", "description": "Stable URL segment identifying this item." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "description": { "description": "Commit only if the previous description value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Purpose and scope of the team inbox." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "purpose": { "description": "Commit only if the previous purpose value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "enum": [ "support", "reception" ], "description": "Whether the inbox handles customer support or reception." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "accent": { "description": "Commit only if the previous accent value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "enum": [ "green", "blue", "amber", "violet", "neutral" ], "description": "Display color token; it does not change routing or access." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "default_assignee_ref": { "description": "Commit only if the previous default_assignee_ref value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "auto_assign_on_reply": { "description": "Commit only if the previous auto_assign_on_reply value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "boolean", "description": "Whether the first member reply assigns an unassigned conversation to that member." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "agent_first_email": { "description": "Commit only if the previous agent_first_email value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "boolean", "description": "Whether the inbox agent takes the first turn on incoming email before escalating work to a person." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "agent_first_web_chat": { "description": "Commit only if the previous agent_first_web_chat value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "boolean", "description": "Whether the inbox agent takes the first turn on incoming web chat before escalating work to a person." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "round_robin": { "description": "Commit only if the previous round_robin value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "boolean", "description": "Saved round-robin preference. This setting does not currently cause automatic assignment." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "playbook_md": { "description": "Commit only if the previous playbook_md value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Shared answering and escalation instructions in Markdown." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "voice_playbook_md": { "description": "Commit only if the previous voice_playbook_md value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Additional instructions for spoken phone conversations; the shared playbook still applies." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "signature_md": { "description": "Commit only if the previous signature_md value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Markdown footer appended to outgoing replies from this inbox." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "web_chat_welcome": { "description": "Commit only if the previous web_chat_welcome value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Welcome message shown to web chat visitors. Empty or absent uses the localized default." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "doc_folders": { "description": "Commit only if the previous doc_folders value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "type": "object", "properties": { "scope": { "type": "string", "description": "Document collection scope containing the folder." }, "path": { "type": "string", "description": "Path to the folder within the document collection." } }, "additionalProperties": false }, "description": "Document folders made available as reference material to this inbox." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] } } } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_inbox_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "deleted": { "type": "string", "enum": [ "deleted", "already_deleted" ], "description": "deleted when this request removed the record; already_deleted when it was already absent." }, "cascaded": { "type": "array", "items": { "type": "string" }, "description": "IDs of dependent records deleted with this record." } }, "required": [ "deleted" ], "additionalProperties": false, "examples": [ { "deleted": "deleted" } ] } ``` --- # Update inbox Update an inbox by ID. Omitted fields stay unchanged; use unset to remove fields and expected to prevent overwriting a concurrent change. POST https://api.brigg.app/v1/operations/support.UpdateInbox ## Access & visibility Allow `support.UpdateInbox` on your API key. Resource read permissions: `core:Inbox`. Resource write permissions: `core:Inbox`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:Inbox` record. Find it with [support.ListInboxes](/developers/reference/support/ListInboxes). Use the record's top-level `id`, not a business field or account ID. | | `data` | [Inbox](#inbox-request-data) | No | The fields to set. | | `unset` | array of string | No | Keys of `data` to remove. Each item: `"name"`, `"slug"`, `"description"`, `"purpose"`, `"accent"`, `"default_assignee_ref"`, `"auto_assign_on_reply"`, `"agent_first_email"`, `"agent_first_web_chat"`, `"round_robin"`, `"playbook_md"`, `"voice_playbook_md"`, `"signature_md"`, `"web_chat_welcome"`, `"doc_folders"`. | | `expected` | [object](#request-expected) | No | Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {"$absent":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource. | ### Inbox · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | No | Team inbox display name. | | `slug` | string | No | Stable URL segment identifying this item. Pattern: `^[a-z][a-z0-9-]*$`. | | `description` | string | No | Purpose and scope of the team inbox. | | `purpose` | string | No | Whether the inbox handles customer support or reception. Allowed: `"support"`, `"reception"`. | | `accent` | string | No | Display color token; it does not change routing or access. Allowed: `"green"`, `"blue"`, `"amber"`, `"violet"`, `"neutral"`. | | `default_assignee_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `auto_assign_on_reply` | boolean | No | Whether the first member reply assigns an unassigned conversation to that member. | | `agent_first_email` | boolean | No | Whether the inbox agent takes the first turn on incoming email before escalating work to a person. | | `agent_first_web_chat` | boolean | No | Whether the inbox agent takes the first turn on incoming web chat before escalating work to a person. | | `round_robin` | boolean | No | Saved round-robin preference. This setting does not currently cause automatic assignment. | | `playbook_md` | string | No | Shared answering and escalation instructions in Markdown. | | `voice_playbook_md` | string | No | Additional instructions for spoken phone conversations; the shared playbook still applies. | | `signature_md` | string | No | Markdown footer appended to outgoing replies from this inbox. | | `web_chat_welcome` | string | No | Welcome message shown to web chat visitors. Empty or absent uses the localized default. | | `doc_folders` | array of [object](#request-data-doc-folders) | No | Document folders made available as reference material to this inbox. | ### request.data.doc_folders[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `scope` | string | No | Document collection scope containing the folder. | | `path` | string | No | Path to the folder within the document collection. | ### request.expected | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string or [object](#request-expected-name) | No | Commit only if the previous name value matches; use $absent to require that this field is missing. | | `slug` | string or [object](#request-expected-slug) | No | Commit only if the previous slug value matches; use $absent to require that this field is missing. | | `description` | string or [object](#request-expected-description) | No | Commit only if the previous description value matches; use $absent to require that this field is missing. | | `purpose` | string or [object](#request-expected-purpose) | No | Commit only if the previous purpose value matches; use $absent to require that this field is missing. | | `accent` | string or [object](#request-expected-accent) | No | Commit only if the previous accent value matches; use $absent to require that this field is missing. | | `default_assignee_ref` | string or [object](#request-expected-default-assignee-ref) | No | Commit only if the previous default_assignee_ref value matches; use $absent to require that this field is missing. | | `auto_assign_on_reply` | boolean or [object](#request-expected-auto-assign-on-reply) | No | Commit only if the previous auto_assign_on_reply value matches; use $absent to require that this field is missing. | | `agent_first_email` | boolean or [object](#request-expected-agent-first-email) | No | Commit only if the previous agent_first_email value matches; use $absent to require that this field is missing. | | `agent_first_web_chat` | boolean or [object](#request-expected-agent-first-web-chat) | No | Commit only if the previous agent_first_web_chat value matches; use $absent to require that this field is missing. | | `round_robin` | boolean or [object](#request-expected-round-robin) | No | Commit only if the previous round_robin value matches; use $absent to require that this field is missing. | | `playbook_md` | string or [object](#request-expected-playbook-md) | No | Commit only if the previous playbook_md value matches; use $absent to require that this field is missing. | | `voice_playbook_md` | string or [object](#request-expected-voice-playbook-md) | No | Commit only if the previous voice_playbook_md value matches; use $absent to require that this field is missing. | | `signature_md` | string or [object](#request-expected-signature-md) | No | Commit only if the previous signature_md value matches; use $absent to require that this field is missing. | | `web_chat_welcome` | string or [object](#request-expected-web-chat-welcome) | No | Commit only if the previous web_chat_welcome value matches; use $absent to require that this field is missing. | | `doc_folders` | array of [object](#request-expected-doc-folders) or [object](#request-expected-doc-folders) | No | Commit only if the previous doc_folders value matches; use $absent to require that this field is missing. | ### request.expected.name | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.slug | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.description | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.purpose | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.accent | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.default_assignee_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.auto_assign_on_reply | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.agent_first_email | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.agent_first_web_chat | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.round_robin | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.playbook_md | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.voice_playbook_md | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.signature_md | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.web_chat_welcome | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.doc_folders | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.doc_folders[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `scope` | string | No | Document collection scope containing the folder. | | `path` | string | No | Path to the folder within the document collection. | ## Update without losing changes Send only the business fields you want to change in `data`; omitted fields stay unchanged. Use `unset` to remove an optional field. Setting a field to null is a different action and is allowed only when its schema permits null. Use `expected` for a conditional update: supply the values you last read for the fields whose concurrent changes would matter. `{"$absent": true}` expects a missing field. A conflict means you must read the record again and decide how to reconcile the change. Keep the same idempotency key when retrying the original action; use a new key for a revised action. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [InboxRecord](#inboxrecord-response-item) | Yes | The requested record, including its metadata and data fields. | ### InboxRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Inbox record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Inbox](#inbox-response-item-data) | Yes | The record's fields. | ### Inbox · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Team inbox display name. | | `slug` | string | No | Stable URL segment identifying this item. Pattern: `^[a-z][a-z0-9-]*$`. | | `description` | string | No | Purpose and scope of the team inbox. | | `purpose` | string | No | Whether the inbox handles customer support or reception. Allowed: `"support"`, `"reception"`. | | `accent` | string | No | Display color token; it does not change routing or access. Allowed: `"green"`, `"blue"`, `"amber"`, `"violet"`, `"neutral"`. | | `default_assignee_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `auto_assign_on_reply` | boolean | No | Whether the first member reply assigns an unassigned conversation to that member. | | `agent_first_email` | boolean | No | Whether the inbox agent takes the first turn on incoming email before escalating work to a person. | | `agent_first_web_chat` | boolean | No | Whether the inbox agent takes the first turn on incoming web chat before escalating work to a person. | | `round_robin` | boolean | No | Saved round-robin preference. This setting does not currently cause automatic assignment. | | `playbook_md` | string | No | Shared answering and escalation instructions in Markdown. | | `voice_playbook_md` | string | No | Additional instructions for spoken phone conversations; the shared playbook still applies. | | `signature_md` | string | No | Markdown footer appended to outgoing replies from this inbox. | | `web_chat_welcome` | string | No | Welcome message shown to web chat visitors. Empty or absent uses the localized default. | | `doc_folders` | array of [object](#response-item-data-doc-folders) | No | Document folders made available as reference material to this inbox. | ### response.item.data.doc_folders[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `scope` | string | No | Document collection scope containing the folder. | | `path` | string | No | Path to the folder within the document collection. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `conflict` | A supplied expected value no longer matches. Read the record again before deciding whether to retry. | ## Next steps - [List inboxes](/developers/reference/support/ListInboxes) - [Get inbox](/developers/reference/support/GetInbox) - [Delete inbox](/developers/reference/support/DeleteInbox) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.UpdateInbox' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_inbox_example", "data": { "description": "Product questions and onboarding support" } }' ``` #### TypeScript ```typescript 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/support.UpdateInbox", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_inbox_example", "data": { "description": "Product questions and onboarding support" } }), }); 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_inbox_example", "data": { "description": "Product questions and onboarding support" } } request = Request( "https://api.brigg.app/v1/operations/support.UpdateInbox", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_inbox_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "Customer support", "slug": "support", "purpose": "support", "auto_assign_on_reply": true, "playbook_md": "Answer product questions. Escalate billing disputes to a person.", "description": "Product questions and onboarding support" } } } ``` ### Update only if unchanged Use a value you actually read. A concurrent change refuses the write with 409 conflict. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.UpdateInbox' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_inbox_example", "data": { "description": "Product questions and onboarding support" }, "expected": { "name": "Customer support" } }' ``` #### TypeScript ```typescript 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/support.UpdateInbox", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_inbox_example", "data": { "description": "Product questions and onboarding support" }, "expected": { "name": "Customer support" } }), }); 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_inbox_example", "data": { "description": "Product questions and onboarding support" }, "expected": { "name": "Customer support" } } request = Request( "https://api.brigg.app/v1/operations/support.UpdateInbox", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_inbox_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "Customer support", "slug": "support", "purpose": "support", "auto_assign_on_reply": true, "playbook_md": "Answer product questions. Escalate billing disputes to a person.", "description": "Product questions and onboarding support" } } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:Inbox` record. Find it with [support.ListInboxes](/developers/reference/support/ListInboxes). Use the record's top-level `id`, not a business field or account ID." }, "data": { "type": "object", "properties": { "name": { "type": "string", "description": "Team inbox display name." }, "slug": { "type": "string", "pattern": "^[a-z][a-z0-9-]*$", "description": "Stable URL segment identifying this item." }, "description": { "type": "string", "description": "Purpose and scope of the team inbox." }, "purpose": { "type": "string", "enum": [ "support", "reception" ], "description": "Whether the inbox handles customer support or reception." }, "accent": { "type": "string", "enum": [ "green", "blue", "amber", "violet", "neutral" ], "description": "Display color token; it does not change routing or access." }, "default_assignee_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "auto_assign_on_reply": { "type": "boolean", "description": "Whether the first member reply assigns an unassigned conversation to that member." }, "agent_first_email": { "type": "boolean", "description": "Whether the inbox agent takes the first turn on incoming email before escalating work to a person." }, "agent_first_web_chat": { "type": "boolean", "description": "Whether the inbox agent takes the first turn on incoming web chat before escalating work to a person." }, "round_robin": { "type": "boolean", "description": "Saved round-robin preference. This setting does not currently cause automatic assignment." }, "playbook_md": { "type": "string", "description": "Shared answering and escalation instructions in Markdown." }, "voice_playbook_md": { "type": "string", "description": "Additional instructions for spoken phone conversations; the shared playbook still applies." }, "signature_md": { "type": "string", "description": "Markdown footer appended to outgoing replies from this inbox." }, "web_chat_welcome": { "type": "string", "description": "Welcome message shown to web chat visitors. Empty or absent uses the localized default." }, "doc_folders": { "type": "array", "items": { "type": "object", "properties": { "scope": { "type": "string", "description": "Document collection scope containing the folder." }, "path": { "type": "string", "description": "Path to the folder within the document collection." } }, "additionalProperties": false }, "description": "Document folders made available as reference material to this inbox." } }, "required": [], "additionalProperties": false, "description": "The fields to set.", "title": "Inbox" }, "unset": { "type": "array", "items": { "type": "string", "enum": [ "name", "slug", "description", "purpose", "accent", "default_assignee_ref", "auto_assign_on_reply", "agent_first_email", "agent_first_web_chat", "round_robin", "playbook_md", "voice_playbook_md", "signature_md", "web_chat_welcome", "doc_folders" ] }, "description": "Keys of `data` to remove." }, "expected": { "type": "object", "description": "Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {\"$absent\":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource.", "additionalProperties": false, "properties": { "name": { "description": "Commit only if the previous name value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Team inbox display name." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "slug": { "description": "Commit only if the previous slug value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "pattern": "^[a-z][a-z0-9-]*$", "description": "Stable URL segment identifying this item." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "description": { "description": "Commit only if the previous description value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Purpose and scope of the team inbox." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "purpose": { "description": "Commit only if the previous purpose value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "enum": [ "support", "reception" ], "description": "Whether the inbox handles customer support or reception." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "accent": { "description": "Commit only if the previous accent value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "enum": [ "green", "blue", "amber", "violet", "neutral" ], "description": "Display color token; it does not change routing or access." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "default_assignee_ref": { "description": "Commit only if the previous default_assignee_ref value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "auto_assign_on_reply": { "description": "Commit only if the previous auto_assign_on_reply value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "boolean", "description": "Whether the first member reply assigns an unassigned conversation to that member." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "agent_first_email": { "description": "Commit only if the previous agent_first_email value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "boolean", "description": "Whether the inbox agent takes the first turn on incoming email before escalating work to a person." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "agent_first_web_chat": { "description": "Commit only if the previous agent_first_web_chat value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "boolean", "description": "Whether the inbox agent takes the first turn on incoming web chat before escalating work to a person." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "round_robin": { "description": "Commit only if the previous round_robin value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "boolean", "description": "Saved round-robin preference. This setting does not currently cause automatic assignment." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "playbook_md": { "description": "Commit only if the previous playbook_md value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Shared answering and escalation instructions in Markdown." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "voice_playbook_md": { "description": "Commit only if the previous voice_playbook_md value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Additional instructions for spoken phone conversations; the shared playbook still applies." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "signature_md": { "description": "Commit only if the previous signature_md value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Markdown footer appended to outgoing replies from this inbox." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "web_chat_welcome": { "description": "Commit only if the previous web_chat_welcome value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Welcome message shown to web chat visitors. Empty or absent uses the localized default." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "doc_folders": { "description": "Commit only if the previous doc_folders value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "type": "object", "properties": { "scope": { "type": "string", "description": "Document collection scope containing the folder." }, "path": { "type": "string", "description": "Path to the folder within the document collection." } }, "additionalProperties": false }, "description": "Document folders made available as reference material to this inbox." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] } } } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_inbox_example", "data": { "description": "Product questions and onboarding support" } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:Inbox record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "name": { "type": "string", "description": "Team inbox display name." }, "slug": { "type": "string", "pattern": "^[a-z][a-z0-9-]*$", "description": "Stable URL segment identifying this item." }, "description": { "type": "string", "description": "Purpose and scope of the team inbox." }, "purpose": { "type": "string", "enum": [ "support", "reception" ], "description": "Whether the inbox handles customer support or reception." }, "accent": { "type": "string", "enum": [ "green", "blue", "amber", "violet", "neutral" ], "description": "Display color token; it does not change routing or access." }, "default_assignee_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "auto_assign_on_reply": { "type": "boolean", "description": "Whether the first member reply assigns an unassigned conversation to that member." }, "agent_first_email": { "type": "boolean", "description": "Whether the inbox agent takes the first turn on incoming email before escalating work to a person." }, "agent_first_web_chat": { "type": "boolean", "description": "Whether the inbox agent takes the first turn on incoming web chat before escalating work to a person." }, "round_robin": { "type": "boolean", "description": "Saved round-robin preference. This setting does not currently cause automatic assignment." }, "playbook_md": { "type": "string", "description": "Shared answering and escalation instructions in Markdown." }, "voice_playbook_md": { "type": "string", "description": "Additional instructions for spoken phone conversations; the shared playbook still applies." }, "signature_md": { "type": "string", "description": "Markdown footer appended to outgoing replies from this inbox." }, "web_chat_welcome": { "type": "string", "description": "Welcome message shown to web chat visitors. Empty or absent uses the localized default." }, "doc_folders": { "type": "array", "items": { "type": "object", "properties": { "scope": { "type": "string", "description": "Document collection scope containing the folder." }, "path": { "type": "string", "description": "Path to the folder within the document collection." } }, "additionalProperties": false }, "description": "Document folders made available as reference material to this inbox." } }, "required": [ "name" ], "additionalProperties": false, "description": "The record's fields.", "title": "Inbox" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "InboxRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_inbox_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "Customer support", "slug": "support", "purpose": "support", "auto_assign_on_reply": true, "playbook_md": "Answer product questions. Escalate billing disputes to a person.", "description": "Product questions and onboarding support" } } } ] } ``` --- # Get inbox message Read an inbox message by ID. Returns item: null when no visible record matches. POST https://api.brigg.app/v1/operations/support.GetInboxMessage ## Access & visibility Allow `support.GetInboxMessage` on your API key. Resource read permissions: `core:InboxMessage`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:InboxMessage` record. Use the relevant list operation to discover records. Use the record's top-level `id`, not a business field or account ID. | ## Response Returns **200 OK** with a JSON body. `item: null` means there is no matching record visible to this caller. It does not reveal whether an inaccessible record exists. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. Messages are read-only through record operations. Creating a customer reply requires the supported messaging workflow, not writing a message record. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [InboxMessageRecord](#inboxmessagerecord-response-item) or null | Yes | null when no such record | ### InboxMessageRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:InboxMessage record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [InboxMessage](#inboxmessage-response-item-data) | Yes | The record's fields. | ### InboxMessage · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `conversation_ref` | string | Yes | ID of a `core:Conversation` record. Find it with [support.ListConversations](/developers/reference/support/ListConversations) and use the top-level `id`. This is not an account ID or a display name. | | `sender_role` | string | Yes | Who produced the message: customer contact, automated agent, workspace member or system. Allowed: `"contact"`, `"agent"`, `"member"`, `"system"`. | | `sender_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `channel` | string | No | Channel carrying the message. Internal notes use internal and are not customer replies. Allowed: `"email"`, `"web_chat"`, `"contact_form"`, `"sms"`, `"phone"`, `"internal"`. | | `direction` | string | No | Inbound from a customer, outbound to a customer, or internal to the support team. Allowed: `"inbound"`, `"outbound"`, `"internal"`. | | `body` | string | No | Message content as stored for its channel. | | `event` | string | No | System event associated with the message, when present. | | `attachments` | array of [object](#response-item-data-attachments) | No | Attachments with a file ID, original filename and size in bytes. | | `delivery` | string | No | Recorded delivery state: queued, sent, delivered or failed. Sent does not guarantee receipt. Allowed: `"queued"`, `"sent"`, `"delivered"`, `"failed"`. | | `delivery_reason` | string | No | Reason reported for a delivery refusal or failure. Present only when a reason has been recorded. Allowed: `"empty"`, `"not_a_number"`, `"wrong_length"`, `"unsupported_country"`, `"needs_number_sender"`, `"not_textable"`, `"sms_not_configured"`, `"quota_exceeded"`, `"carrier_rejected"`, `"email_bounced"`, `"email_complaint"`. | ### response.item.data.attachments[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `file_id` | string | No | File identifier. | | `filename` | string | No | Original filename, including its extension. | | `size` | number | No | File size in bytes. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [List inbox messages](/developers/reference/support/ListInboxMessages) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.GetInboxMessage' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "e_inboxmessage_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/support.GetInboxMessage", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "id": "e_inboxmessage_example" }), }); 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 payload = { "id": "e_inboxmessage_example" } request = Request( "https://api.brigg.app/v1/operations/support.GetInboxMessage", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "item": { "id": "e_inboxmessage_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "conversation_ref": "e_conversation_onboarding", "sender_role": "contact", "channel": "email", "direction": "inbound", "body": "Can you help us import our contacts?" } } } ``` ### No visible record A missing or inaccessible record returns item: null. Do not treat this as proof that a record exists for another member. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.GetInboxMessage' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "e_inboxmessage_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/support.GetInboxMessage", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "id": "e_inboxmessage_example" }), }); 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 payload = { "id": "e_inboxmessage_example" } request = Request( "https://api.brigg.app/v1/operations/support.GetInboxMessage", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "item": null } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:InboxMessage` record. Use the relevant list operation to discover records. Use the record's top-level `id`, not a business field or account ID." } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_inboxmessage_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": [ "object", "null" ], "properties": { "id": { "type": "string", "description": "Stable core:InboxMessage record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "conversation_ref": { "type": "string", "description": "ID of a `core:Conversation` record. Find it with [support.ListConversations](/developers/reference/support/ListConversations) and use the top-level `id`. This is not an account ID or a display name." }, "sender_role": { "type": "string", "enum": [ "contact", "agent", "member", "system" ], "description": "Who produced the message: customer contact, automated agent, workspace member or system." }, "sender_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "channel": { "type": "string", "enum": [ "email", "web_chat", "contact_form", "sms", "phone", "internal" ], "description": "Channel carrying the message. Internal notes use internal and are not customer replies." }, "direction": { "type": "string", "enum": [ "inbound", "outbound", "internal" ], "description": "Inbound from a customer, outbound to a customer, or internal to the support team." }, "body": { "type": "string", "description": "Message content as stored for its channel." }, "event": { "type": "string", "description": "System event associated with the message, when present." }, "attachments": { "type": "array", "items": { "type": "object", "properties": { "file_id": { "type": "string", "description": "File identifier." }, "filename": { "type": "string", "description": "Original filename, including its extension." }, "size": { "type": "number", "description": "File size in bytes." } }, "additionalProperties": false }, "description": "Attachments with a file ID, original filename and size in bytes." }, "delivery": { "type": "string", "enum": [ "queued", "sent", "delivered", "failed" ], "description": "Recorded delivery state: queued, sent, delivered or failed. Sent does not guarantee receipt." }, "delivery_reason": { "type": "string", "enum": [ "empty", "not_a_number", "wrong_length", "unsupported_country", "needs_number_sender", "not_textable", "sms_not_configured", "quota_exceeded", "carrier_rejected", "email_bounced", "email_complaint" ], "description": "Reason reported for a delivery refusal or failure. Present only when a reason has been recorded." } }, "required": [ "conversation_ref", "sender_role" ], "additionalProperties": false, "description": "The record's fields.", "title": "InboxMessage" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "null when no such record", "title": "InboxMessageRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_inboxmessage_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "conversation_ref": "e_conversation_onboarding", "sender_role": "contact", "channel": "email", "direction": "inbound", "body": "Can you help us import our contacts?" } } } ] } ``` --- # List inbox messages List inbox messages visible to the credential, with filtering, sorting and cursor pagination. POST https://api.brigg.app/v1/operations/support.ListInboxMessages ## Access & visibility Allow `support.ListInboxMessages` on your API key. Resource read permissions: `core:InboxMessage`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `filters` | array of [object](#request-filters) | No | Conditions the row must ALL satisfy. | | `sort` | [object](#request-sort) | No | Sort order for the results. Defaults to updated_at descending, with id as a tie-breaker. | | `limit` | integer | No | Maximum number of results to return in this page. Continue with next_cursor when returned. Default: `100`. Minimum: 1. | | `cursor` | string | No | The `next_cursor` of the previous page. | ### request.filters[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | `data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private. Allowed: `"id"`, `"created_at"`, `"updated_at"`, `"created_by"`, `"private"`, `"data.conversation_ref"`, `"data.sender_role"`, `"data.sender_ref"`, `"data.channel"`, `"data.direction"`, `"data.body"`, `"data.event"`, `"data.attachments"`, `"data.delivery"`, `"data.delivery_reason"`. | | `op` | string | Yes | Comparison operator. Use in with an array, or omit value for is_empty and is_not_empty. Allowed: `"eq"`, `"neq"`, `"contains"`, `"starts_with"`, `"gt"`, `"gte"`, `"lt"`, `"lte"`, `"in"`, `"has"`, `"is_empty"`, `"is_not_empty"`. | | `value` | JSON value | No | The comparison value; an array for `in`; omitted for is_empty / is_not_empty. | ### request.sort | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | `data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private. Allowed: `"id"`, `"created_at"`, `"updated_at"`, `"created_by"`, `"private"`, `"data.conversation_ref"`, `"data.sender_role"`, `"data.sender_ref"`, `"data.channel"`, `"data.direction"`, `"data.body"`, `"data.event"`, `"data.attachments"`, `"data.delivery"`, `"data.delivery_reason"`. | | `direction` | string | No | Sort direction: asc for ascending or desc for descending. Allowed: `"asc"`, `"desc"`. | ## Filtering and sorting All conditions are combined with **AND**. Address business fields as `data.`, and record metadata as `id`, `created_at`, `updated_at`, `created_by` or `private`. A field path names one field; it does not traverse nested objects. | Operator | Meaning | Value | | --- | --- | --- | | `eq` | Equal to a scalar | String, number, boolean or null | | `neq` | Not equal; missing values also match | String, number, boolean or null | | `contains` | Case-insensitive text contains | String; % and _ are literal characters | | `starts_with` | Case-insensitive text prefix | String | | `gt`, `gte` | Greater than / at least | Number or string appropriate to the field | | `lt`, `lte` | Less than / at most | Number or string appropriate to the field | | `in` | Equal to any supplied scalar | Nonempty array of strings, numbers, booleans or null | | `has` | Array contains a string | One string; does not match properties inside array objects | | `is_empty` | Missing, null, empty string or empty array | Omit value | | `is_not_empty` | Has a nonempty value | Omit value | Match the stored field's type. Numeric business timestamps take Unix milliseconds; date-only business fields take `YYYY-MM-DD`. The record metadata fields `created_at` and `updated_at` also accept ISO timestamps for ordered comparisons. Sorting defaults to `updated_at` descending. If you supply `sort.field` without `sort.direction`, direction is `desc`. The record ID breaks ties; missing values sort last. ## Response Returns **200 OK** with a JSON body. An empty `items` array means this page contains no matching visible results. Follow `next_cursor` when present. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. Messages are read-only through record operations. Creating a customer reply requires the supported messaging workflow, not writing a message record. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [InboxMessageRecord](#inboxmessagerecord-response-items) | Yes | Records visible under the credential's grants and the selected data scope, matching the requested filters. Pass next_cursor as cursor to continue when a next cursor is returned. | | `next_cursor` | string | No | Pass this value as cursor to continue with the same filters, sort and credential. Omitted when there are no more results. | ### InboxMessageRecord · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:InboxMessage record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [InboxMessage](#inboxmessage-response-items-data) | Yes | The record's fields. | ### InboxMessage · response.items[].data | Field | Type | Required | Description | | --- | --- | --- | --- | | `conversation_ref` | string | Yes | ID of a `core:Conversation` record. Find it with [support.ListConversations](/developers/reference/support/ListConversations) and use the top-level `id`. This is not an account ID or a display name. | | `sender_role` | string | Yes | Who produced the message: customer contact, automated agent, workspace member or system. Allowed: `"contact"`, `"agent"`, `"member"`, `"system"`. | | `sender_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `channel` | string | No | Channel carrying the message. Internal notes use internal and are not customer replies. Allowed: `"email"`, `"web_chat"`, `"contact_form"`, `"sms"`, `"phone"`, `"internal"`. | | `direction` | string | No | Inbound from a customer, outbound to a customer, or internal to the support team. Allowed: `"inbound"`, `"outbound"`, `"internal"`. | | `body` | string | No | Message content as stored for its channel. | | `event` | string | No | System event associated with the message, when present. | | `attachments` | array of [object](#response-items-data-attachments) | No | Attachments with a file ID, original filename and size in bytes. | | `delivery` | string | No | Recorded delivery state: queued, sent, delivered or failed. Sent does not guarantee receipt. Allowed: `"queued"`, `"sent"`, `"delivered"`, `"failed"`. | | `delivery_reason` | string | No | Reason reported for a delivery refusal or failure. Present only when a reason has been recorded. Allowed: `"empty"`, `"not_a_number"`, `"wrong_length"`, `"unsupported_country"`, `"needs_number_sender"`, `"not_textable"`, `"sms_not_configured"`, `"quota_exceeded"`, `"carrier_rejected"`, `"email_bounced"`, `"email_complaint"`. | ### response.items[].data.attachments[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `file_id` | string | No | File identifier. | | `filename` | string | No | Original filename, including its extension. | | `size` | number | No | File size in bytes. | ## Pagination Pass `next_cursor` from the response as `cursor` on the next request. Keep the same filters, sort and acting identity. Stop when `next_cursor` is absent; do not infer completion from the number of items. The default page size is **100**; `limit` must be a positive integer. **Pagination is a live view, not a snapshot.** Changes between pages can move records across page boundaries. Upsert by record ID rather than appending blindly. For recurring synchronization, use an overlapping update window and deduplicate records. Periodically reconcile IDs to detect deletions. [Resource webhooks](/developers/webhooks) can supplement synchronization for eligible workspace-shared records only: they do not export private or project-scoped records. Personal data still needs polling and reconciliation. ```typescript const query = { "limit": 10 }; let cursor; do { const response = await fetch("https://api.brigg.app/v1/operations/support.ListInboxMessages", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ ...query, ...(cursor ? { cursor } : {}) }), }); const page = await response.json(); if (!response.ok) throw new Error(`${response.status}: ${page.message}`); for (const item of page.items) { console.log(item); // Process or upsert each result. } cursor = page.next_cursor; } while (cursor); ``` ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | | 400 | `cursor_invalid` | Restart pagination with no cursor. | | 400 | `cursor_mismatch` | Use the cursor with the original filters, sort order and credential. | ## Next steps - [Get inbox message](/developers/reference/support/GetInboxMessage) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### First page Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.ListInboxMessages' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "limit": 10 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/support.ListInboxMessages", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "limit": 10 }), }); 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 payload = { "limit": 10 } request = Request( "https://api.brigg.app/v1/operations/support.ListInboxMessages", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_inboxmessage_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "conversation_ref": "e_conversation_onboarding", "sender_role": "contact", "channel": "email", "direction": "inbound", "body": "Can you help us import our contacts?" } } ] } ``` ### Messages in a conversation Read a case's messages chronologically. Internal notes and customer-facing replies remain distinguishable by channel and direction. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.ListInboxMessages' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "limit": 50, "filters": [ { "field": "data.conversation_ref", "op": "eq", "value": "e_conversation_onboarding" } ], "sort": { "field": "created_at", "direction": "asc" } }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/support.ListInboxMessages", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "limit": 50, "filters": [ { "field": "data.conversation_ref", "op": "eq", "value": "e_conversation_onboarding" } ], "sort": { "field": "created_at", "direction": "asc" } }), }); 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 payload = { "limit": 50, "filters": [ { "field": "data.conversation_ref", "op": "eq", "value": "e_conversation_onboarding" } ], "sort": { "field": "created_at", "direction": "asc" } } request = Request( "https://api.brigg.app/v1/operations/support.ListInboxMessages", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_inboxmessage_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "conversation_ref": "e_conversation_onboarding", "sender_role": "contact", "channel": "email", "direction": "inbound", "body": "Can you help us import our contacts?" } } ] } ``` ### Records updated since a checkpoint 6 October 2026 at 00:00 UTC. Use an overlap window and upsert by ID when synchronizing. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.ListInboxMessages' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/support.ListInboxMessages", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 }), }); 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 payload = { "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 } request = Request( "https://api.brigg.app/v1/operations/support.ListInboxMessages", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_inboxmessage_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "conversation_ref": "e_conversation_onboarding", "sender_role": "contact", "channel": "email", "direction": "inbound", "body": "Can you help us import our contacts?" } } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "filters": { "type": "array", "items": { "type": "object", "properties": { "field": { "type": "string", "description": "`data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private.", "enum": [ "id", "created_at", "updated_at", "created_by", "private", "data.conversation_ref", "data.sender_role", "data.sender_ref", "data.channel", "data.direction", "data.body", "data.event", "data.attachments", "data.delivery", "data.delivery_reason" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "contains", "starts_with", "gt", "gte", "lt", "lte", "in", "has", "is_empty", "is_not_empty" ], "description": "Comparison operator. Use in with an array, or omit value for is_empty and is_not_empty." }, "value": { "description": "The comparison value; an array for `in`; omitted for is_empty / is_not_empty." } }, "required": [ "field", "op" ], "additionalProperties": false }, "description": "Conditions the row must ALL satisfy." }, "sort": { "type": "object", "properties": { "field": { "type": "string", "description": "`data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private.", "enum": [ "id", "created_at", "updated_at", "created_by", "private", "data.conversation_ref", "data.sender_role", "data.sender_ref", "data.channel", "data.direction", "data.body", "data.event", "data.attachments", "data.delivery", "data.delivery_reason" ] }, "direction": { "type": "string", "enum": [ "asc", "desc" ], "description": "Sort direction: asc for ascending or desc for descending." } }, "required": [ "field" ], "additionalProperties": false, "description": "Sort order for the results. Defaults to updated_at descending, with id as a tie-breaker." }, "limit": { "type": "integer", "minimum": 1, "default": 100, "description": "Maximum number of results to return in this page. Continue with next_cursor when returned." }, "cursor": { "type": "string", "description": "The `next_cursor` of the previous page." } }, "additionalProperties": false, "examples": [ { "limit": 10 } ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:InboxMessage record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "conversation_ref": { "type": "string", "description": "ID of a `core:Conversation` record. Find it with [support.ListConversations](/developers/reference/support/ListConversations) and use the top-level `id`. This is not an account ID or a display name." }, "sender_role": { "type": "string", "enum": [ "contact", "agent", "member", "system" ], "description": "Who produced the message: customer contact, automated agent, workspace member or system." }, "sender_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "channel": { "type": "string", "enum": [ "email", "web_chat", "contact_form", "sms", "phone", "internal" ], "description": "Channel carrying the message. Internal notes use internal and are not customer replies." }, "direction": { "type": "string", "enum": [ "inbound", "outbound", "internal" ], "description": "Inbound from a customer, outbound to a customer, or internal to the support team." }, "body": { "type": "string", "description": "Message content as stored for its channel." }, "event": { "type": "string", "description": "System event associated with the message, when present." }, "attachments": { "type": "array", "items": { "type": "object", "properties": { "file_id": { "type": "string", "description": "File identifier." }, "filename": { "type": "string", "description": "Original filename, including its extension." }, "size": { "type": "number", "description": "File size in bytes." } }, "additionalProperties": false }, "description": "Attachments with a file ID, original filename and size in bytes." }, "delivery": { "type": "string", "enum": [ "queued", "sent", "delivered", "failed" ], "description": "Recorded delivery state: queued, sent, delivered or failed. Sent does not guarantee receipt." }, "delivery_reason": { "type": "string", "enum": [ "empty", "not_a_number", "wrong_length", "unsupported_country", "needs_number_sender", "not_textable", "sms_not_configured", "quota_exceeded", "carrier_rejected", "email_bounced", "email_complaint" ], "description": "Reason reported for a delivery refusal or failure. Present only when a reason has been recorded." } }, "required": [ "conversation_ref", "sender_role" ], "additionalProperties": false, "description": "The record's fields.", "title": "InboxMessage" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "title": "InboxMessageRecord" }, "description": "Records visible under the credential's grants and the selected data scope, matching the requested filters. Pass next_cursor as cursor to continue when a next cursor is returned." }, "next_cursor": { "type": "string", "description": "Pass this value as cursor to continue with the same filters, sort and credential. Omitted when there are no more results." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "id": "e_inboxmessage_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "conversation_ref": "e_conversation_onboarding", "sender_role": "contact", "channel": "email", "direction": "inbound", "body": "Can you help us import our contacts?" } } ] } ] } ``` --- # Add inbox note Add a note for colleagues working on a support conversation. The note is never sent to the customer. POST https://api.brigg.app/v1/operations/support.AddInboxNote ## Access & visibility Allow `support.AddInboxNote` on your API key. Resource write permissions: `core:InboxMessage`. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `conversation_id` | string | Yes | Use the conversation record's top-level id. Its inbox_ref identifies the inbox, not the conversation. [support.ListConversations](/developers/reference/support/ListConversations). At least 1 character. | | `body` | string | Yes | The note, for the team. Plain text. At least 1 character. At most 20000 characters. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | | `message_id` | string | Yes | Message identifier. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | ## Next steps - [List conversations](/developers/reference/support/ListConversations) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.AddInboxNote' \ -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 '{ "conversation_id": "e_example", "body": "Alex asked us to confirm the import format." }' ``` #### 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/support.AddInboxNote", { 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({ "conversation_id": "e_example", "body": "Alex asked us to confirm the import format." }), }); 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 = { "conversation_id": "e_example", "body": "Alex asked us to confirm the import format." } request = Request( "https://api.brigg.app/v1/operations/support.AddInboxNote", 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, "message_id": "e_example" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "conversation_id": { "type": "string", "minLength": 1, "description": "Use the conversation record's top-level id. Its inbox_ref identifies the inbox, not the conversation. [support.ListConversations](/developers/reference/support/ListConversations)." }, "body": { "type": "string", "minLength": 1, "maxLength": 20000, "description": "The note, for the team. Plain text." } }, "required": [ "conversation_id", "body" ], "additionalProperties": false, "examples": [ { "conversation_id": "e_example", "body": "Alex asked us to confirm the import format." } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." }, "message_id": { "type": "string", "description": "Message identifier." } }, "required": [ "ok", "message_id" ], "additionalProperties": false, "examples": [ { "ok": true, "message_id": "e_example" } ] } ``` --- # Get phone number quote Get the current monthly rental and per-minute prices for an inbox phone number. Pass the accepted quote to support.RentPhoneNumber. POST https://api.brigg.app/v1/operations/support.GetPhoneNumberQuote ## Access & visibility Allow `support.GetPhoneNumberQuote` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/permissions) ## Request No parameters. Send an empty JSON object (`{}`). ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `pricing` | [object](#response-pricing) | Yes | Current rental and call prices for the support phone number. | ### response.pricing | Field | Type | Required | Description | | --- | --- | --- | --- | | `monthly_price_nok` | number | Yes | Monthly rental price in Norwegian kroner. | | `per_minute_price_nok` | number | Yes | Call price per minute in Norwegian kroner. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.GetPhoneNumberQuote' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{}' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/support.GetPhoneNumberQuote", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/support.GetPhoneNumberQuote", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "pricing": { "monthly_price_nok": 1, "per_minute_price_nok": 1 } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": {}, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "pricing": { "type": "object", "properties": { "monthly_price_nok": { "type": "number", "description": "Monthly rental price in Norwegian kroner." }, "per_minute_price_nok": { "type": "number", "description": "Call price per minute in Norwegian kroner." } }, "required": [ "monthly_price_nok", "per_minute_price_nok" ], "additionalProperties": false, "description": "Current rental and call prices for the support phone number." } }, "required": [ "pricing" ], "additionalProperties": false, "examples": [ { "pricing": { "monthly_price_nok": 1, "per_minute_price_nok": 1 } } ] } ``` --- # List phone numbers List rented inbox phone numbers and their current channel status. POST https://api.brigg.app/v1/operations/support.ListPhoneNumbers ## Access & visibility Allow `support.ListPhoneNumbers` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/permissions) ## Request No parameters. Send an empty JSON object (`{}`). ## Response Returns **200 OK** with a JSON body. This operation has no continuation cursor. An empty `items` array means no matching visible results were returned. The public API lists team/inbox numbers, not personal assistant lines. Use each e164 value with the configuration and enable operations. Renting or releasing numbers changes billing and is managed by a person in Brigg. An empty list does not prove that the phone service is unavailable; check configured separately. | Field | Type | Required | Description | | --- | --- | --- | --- | | `configured` | boolean | Yes | Whether the phone service is configured to order numbers in this environment. This is not an individual number's activation status; existing rentals can still be listed when false. | | `items` | array of [Support phone number](#support-phone-number-response-items) | Yes | Workspace support phone numbers and their configuration state. This operation has no cursor pagination. | ### Support phone number · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `e164` | string | Yes | Telephone number in international E.164 format, including the leading +. Used as the number's identifier in phone operations. | | `display` | string | No | Human-readable formatting of the phone number. | | `country` | string | No | Two-letter country code of the telephone number, for example NO for Norway. | | `region` | string or null | No | Provider region associated with this number, when supplied. | | `label` | string or null | No | Workspace display label for the number. | | `status` | string | No | Rental lifecycle: provisioning while setup is pending, active when provisioned, suspended when service is held, releasing during removal, or released after removal. An active rental can still have calling disabled on its inbox. | | `usage` | string | No | Configured use: own_number is a standalone support number; forward receives calls forwarded from an existing number. Allowed: `"own_number"`, `"forward"`. | | `monthly_price_nok` | number | No | Monthly rental price in Norwegian kroner. | | `per_minute_price_nok` | number | No | Call price per minute in Norwegian kroner. | | `agreed_at` | number or null | No | Time the rental terms were accepted, in Unix milliseconds. | | `next_rental_charge_at` | number or null | No | Next rental charge time in Unix milliseconds, or null if none is scheduled. | | `created_at` | number | No | Time the number was added to the workspace, in Unix milliseconds. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 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. | ## Next steps - [Configure phone number](/developers/reference/support/ConfigurePhoneNumber) - [Set phone number enabled](/developers/reference/support/SetPhoneNumberEnabled) - [Get phone number quote](/developers/reference/support/GetPhoneNumberQuote) - [List inbox channels](/developers/reference/support/ListInboxChannels) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.ListPhoneNumbers' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Brigg-Act-As: $BRIGG_ACT_AS" \ --data-raw '{}' ``` #### 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 response = await fetch("https://api.brigg.app/v1/operations/support.ListPhoneNumbers", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Brigg-Act-As": actAs, }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/support.ListPhoneNumbers", 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"], }, 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 { "configured": false, "items": [ { "e164": "+4721001234", "display": "+47 21 00 12 34", "country": "NO", "region": "Oslo", "label": "Customer support", "status": "active", "monthly_price_nok": 99, "per_minute_price_nok": 1.5 } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": {}, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "configured": { "type": "boolean", "description": "Whether the phone service is configured to order numbers in this environment. This is not an individual number's activation status; existing rentals can still be listed when false." }, "items": { "type": "array", "items": { "type": "object", "properties": { "e164": { "type": "string", "description": "Telephone number in international E.164 format, including the leading +. Used as the number's identifier in phone operations.", "examples": [ "+4721001234" ] }, "display": { "type": "string", "description": "Human-readable formatting of the phone number.", "examples": [ "+47 21 00 12 34" ] }, "country": { "type": "string", "description": "Two-letter country code of the telephone number, for example NO for Norway.", "examples": [ "NO" ] }, "region": { "type": [ "string", "null" ], "description": "Provider region associated with this number, when supplied.", "examples": [ "Oslo" ] }, "label": { "type": [ "string", "null" ], "description": "Workspace display label for the number.", "examples": [ "Customer support" ] }, "status": { "type": "string", "description": "Rental lifecycle: provisioning while setup is pending, active when provisioned, suspended when service is held, releasing during removal, or released after removal. An active rental can still have calling disabled on its inbox.", "examples": [ "active" ] }, "usage": { "type": "string", "enum": [ "own_number", "forward" ], "description": "Configured use: own_number is a standalone support number; forward receives calls forwarded from an existing number." }, "monthly_price_nok": { "type": "number", "description": "Monthly rental price in Norwegian kroner.", "examples": [ 99 ] }, "per_minute_price_nok": { "type": "number", "description": "Call price per minute in Norwegian kroner.", "examples": [ 1.5 ] }, "agreed_at": { "type": [ "number", "null" ], "description": "Time the rental terms were accepted, in Unix milliseconds." }, "next_rental_charge_at": { "type": [ "number", "null" ], "description": "Next rental charge time in Unix milliseconds, or null if none is scheduled." }, "created_at": { "type": "number", "description": "Time the number was added to the workspace, in Unix milliseconds." } }, "required": [ "e164" ], "additionalProperties": false, "title": "Support phone number" }, "description": "Workspace support phone numbers and their configuration state. This operation has no cursor pagination." } }, "required": [ "items", "configured" ], "additionalProperties": false, "examples": [ { "configured": false, "items": [ { "e164": "+4721001234", "display": "+47 21 00 12 34", "country": "NO", "region": "Oslo", "label": "Customer support", "status": "active", "monthly_price_nok": 99, "per_minute_price_nok": 1.5 } ] } ] } ``` --- # Configure phone number Set the answering voice and language for a rented support number. If activation is still in progress, saving retries activation and reports whether the number is ready. POST https://api.brigg.app/v1/operations/support.ConfigurePhoneNumber ## Access & visibility Allow `support.ConfigurePhoneNumber` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `e164` | string | Yes | Existing rented number from [List phone numbers](/developers/reference/support/ListPhoneNumbers), including the leading + and country calling code. At least 3 characters. | | `settings` | [object](#request-settings) | Yes | Complete replacement of user-editable phone settings. Server-managed routing and greeting configuration are preserved. | ### request.settings | Field | Type | Required | Description | | --- | --- | --- | --- | | `voice_id` | string | Yes | Required compatibility value; currently does not change the receptionist's live voice. Preserve the existing value, or use the documented default in the example. At least 1 character. At most 120 characters. | | `language` | string | No | Language tag such as en, no, sv or da. Defaults to no when omitted; omission does not preserve a previously saved language. Default: `"no"`. At least 2 characters. At most 16 characters. | ## Configure an existing number Get `e164` from [List phone numbers](/developers/reference/support/ListPhoneNumbers). This operation configures an already rented number; it does not rent a number. Send the complete settings pair. `settings` replaces the user-editable settings, while Brigg preserves its own routing configuration. Omitting `language` resets it to `no` (Norwegian), rather than keeping its previous value. Use a language tag such as `en`, `no`, `sv` or `da`. `voice_id` is currently retained for compatibility: changing it does **not** select the live receptionist's voice. Use the example's default when you have no saved value to preserve. Greeting and transfer instructions belong to the inbox playbook, not this object. ## Settings saved does not mean calls are active `ok: true` confirms the settings save. A number still provisioning also returns `activated`: false means carrier activation is incomplete, and `detail` gives its reported state; true means activation completed. When no activation attempt was needed, `activated` is absent. Check [List phone numbers](/developers/reference/support/ListPhoneNumbers) for provisioning progress. Do not release and rent the number again to recover a pending activation. The separate [Set phone number enabled](/developers/reference/support/SetPhoneNumberEnabled) operation controls whether its inbox accepts calls. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | | `activated` | boolean | No | Present only when the number was still provisioning: true if activation completed, false if the carrier is not ready. Absence does not mean false. | | `detail` | string | No | Carrier state explaining activated: false. The settings save has already succeeded. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List phone numbers](/developers/reference/support/ListPhoneNumbers) - [Set phone number enabled](/developers/reference/support/SetPhoneNumberEnabled) - [Get inbox](/developers/reference/support/GetInbox) - [Update inbox](/developers/reference/support/UpdateInbox) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Save English settings Keep the compatibility voice value; language is explicit so this does not reset to Norwegian. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.ConfigurePhoneNumber' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "e164": "+4721001234", "settings": { "voice_id": "xF681s0UeE04gsf0mVsJ", "language": "en" } }' ``` #### TypeScript ```typescript 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/support.ConfigurePhoneNumber", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "e164": "+4721001234", "settings": { "voice_id": "xF681s0UeE04gsf0mVsJ", "language": "en" } }), }); 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 = { "e164": "+4721001234", "settings": { "voice_id": "xF681s0UeE04gsf0mVsJ", "language": "en" } } request = Request( "https://api.brigg.app/v1/operations/support.ConfigurePhoneNumber", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 } ``` ### Activation still pending A successful settings save while the rented number is waiting for its carrier. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.ConfigurePhoneNumber' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "e164": "+4721001234", "settings": { "voice_id": "xF681s0UeE04gsf0mVsJ", "language": "en" } }' ``` #### TypeScript ```typescript 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/support.ConfigurePhoneNumber", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "e164": "+4721001234", "settings": { "voice_id": "xF681s0UeE04gsf0mVsJ", "language": "en" } }), }); 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 = { "e164": "+4721001234", "settings": { "voice_id": "xF681s0UeE04gsf0mVsJ", "language": "en" } } request = Request( "https://api.brigg.app/v1/operations/support.ConfigurePhoneNumber", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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, "activated": false, "detail": "provisioning" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "e164": { "type": "string", "minLength": 3, "description": "Existing rented number from [List phone numbers](/developers/reference/support/ListPhoneNumbers), including the leading + and country calling code." }, "settings": { "type": "object", "properties": { "voice_id": { "type": "string", "minLength": 1, "maxLength": 120, "description": "Required compatibility value; currently does not change the receptionist's live voice. Preserve the existing value, or use the documented default in the example." }, "language": { "type": "string", "minLength": 2, "maxLength": 16, "default": "no", "description": "Language tag such as en, no, sv or da. Defaults to no when omitted; omission does not preserve a previously saved language." } }, "required": [ "voice_id" ], "additionalProperties": false, "description": "Complete replacement of user-editable phone settings. Server-managed routing and greeting configuration are preserved." } }, "required": [ "e164", "settings" ], "additionalProperties": false, "examples": [ { "e164": "+4721001234", "settings": { "voice_id": "xF681s0UeE04gsf0mVsJ", "language": "en" } } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." }, "activated": { "type": "boolean", "description": "Present only when the number was still provisioning: true if activation completed, false if the carrier is not ready. Absence does not mean false." }, "detail": { "type": "string", "description": "Carrier state explaining activated: false. The settings save has already succeeded." } }, "required": [ "ok" ], "additionalProperties": false, "examples": [ { "ok": true } ] } ``` --- # Set phone number enabled Enable or pause a rented phone number's inbox channel after provisioning has completed. POST https://api.brigg.app/v1/operations/support.SetPhoneNumberEnabled ## Access & visibility Allow `support.SetPhoneNumberEnabled` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `e164` | string | Yes | Use the existing number's e164 value including + and the country calling code. This operation does not rent a number. [support.ListPhoneNumbers](/developers/reference/support/ListPhoneNumbers). At least 3 characters. | | `enabled` | boolean | Yes | Whether this feature is enabled. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List phone numbers](/developers/reference/support/ListPhoneNumbers) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.SetPhoneNumberEnabled' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "e164": "+4721001234", "enabled": true }' ``` #### TypeScript ```typescript 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/support.SetPhoneNumberEnabled", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "e164": "+4721001234", "enabled": true }), }); 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 = { "e164": "+4721001234", "enabled": True } request = Request( "https://api.brigg.app/v1/operations/support.SetPhoneNumberEnabled", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "e164": { "type": "string", "minLength": 3, "description": "Use the existing number's e164 value including + and the country calling code. This operation does not rent a number. [support.ListPhoneNumbers](/developers/reference/support/ListPhoneNumbers)." }, "enabled": { "type": "boolean", "description": "Whether this feature is enabled." } }, "required": [ "e164", "enabled" ], "additionalProperties": false, "examples": [ { "e164": "+4721001234", "enabled": true } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." } }, "required": [ "ok" ], "additionalProperties": false, "examples": [ { "ok": true } ] } ``` --- # Set phone number usage Record whether an inbox phone number is used directly as the support number or receives forwarded calls from an existing number. POST https://api.brigg.app/v1/operations/support.SetPhoneNumberUsage ## Access & visibility Allow `support.SetPhoneNumberUsage` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `e164` | string | Yes | Use the existing number's e164 value including + and the country calling code. This operation does not rent a number. [support.ListPhoneNumbers](/developers/reference/support/ListPhoneNumbers). At least 3 characters. | | `usage` | string | Yes | Whether customers call this number directly or reach it through forwarding. Allowed: `"own_number"`, `"forward"`. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List phone numbers](/developers/reference/support/ListPhoneNumbers) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.SetPhoneNumberUsage' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "e164": "+4721001234", "usage": "own_number" }' ``` #### TypeScript ```typescript 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/support.SetPhoneNumberUsage", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "e164": "+4721001234", "usage": "own_number" }), }); 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 = { "e164": "+4721001234", "usage": "own_number" } request = Request( "https://api.brigg.app/v1/operations/support.SetPhoneNumberUsage", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "e164": { "type": "string", "minLength": 3, "description": "Use the existing number's e164 value including + and the country calling code. This operation does not rent a number. [support.ListPhoneNumbers](/developers/reference/support/ListPhoneNumbers)." }, "usage": { "type": "string", "enum": [ "own_number", "forward" ], "description": "Whether customers call this number directly or reach it through forwarding." } }, "required": [ "e164", "usage" ], "additionalProperties": false, "examples": [ { "e164": "+4721001234", "usage": "own_number" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." } }, "required": [ "ok" ], "additionalProperties": false, "examples": [ { "ok": true } ] } ``` --- # Generate inbox reply Generate a draft reply from the visible inbox conversation and its instructions. Nothing is sent until a person reviews and sends it. Uses workspace credits. POST https://api.brigg.app/v1/operations/support.GenerateInboxReply ## Access & visibility Allow `support.GenerateInboxReply` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `conversation_id` | string | Yes | Conversation record ID from ListConversations. Use the same approved member who can read its inbox and messages; an inbox ID is not a conversation ID. At least 1 character. | ## Generate a draft, then review it Find a visible conversation with [List conversations](/developers/reference/support/ListConversations). This call waits for generation and returns the reply body directly; there is no job ID to poll. It uses the visible recent conversation and inbox instructions, excludes internal notes, and charges AI usage to the workspace. Very long threads use the latest 100 messages. Display the returned text in an editable draft and review facts, promises and tone. No message, saved draft or customer notification is created by this call. A person can continue the reply in Brigg. A later generation may return different wording; use the same idempotency key to recover a lost response, and a new key only for a deliberate new generation. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `suggestion` | string | Yes | Generated reply body as a text string, in the customer's language. It is neither saved nor sent. Review and edit it before presenting or sending it to the customer; treat generated text as untrusted content, not HTML. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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` | This member has reached the reply-generation rate limit. Honor Retry-After before retrying. | | 422 | `empty_thread` | The visible conversation has no customer or support message to draft from. Internal notes alone are not enough. | | 503 | `llm_unavailable` | No usable draft was generated. Wait before retrying; no reply was saved or sent. | ## Next steps - [List conversations](/developers/reference/support/ListConversations) - [List inbox messages](/developers/reference/support/ListInboxMessages) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Draft a customer reply The customer asked how to prepare a contacts import. The response is suggested text for review, not a sent message. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.GenerateInboxReply' \ -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 '{ "conversation_id": "e_conversation_contacts" }' ``` #### 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/support.GenerateInboxReply", { 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({ "conversation_id": "e_conversation_contacts" }), }); 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 = { "conversation_id": "e_conversation_contacts" } request = Request( "https://api.brigg.app/v1/operations/support.GenerateInboxReply", 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 { "suggestion": "You can upload a CSV with a header row and one contact per row. Include name and email columns. If you share the column names you use, I can help you check the mapping before importing." } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "conversation_id": { "type": "string", "minLength": 1, "description": "Conversation record ID from ListConversations. Use the same approved member who can read its inbox and messages; an inbox ID is not a conversation ID." } }, "required": [ "conversation_id" ], "additionalProperties": false, "examples": [ { "conversation_id": "e_conversation_contacts" } ] } ``` ```json-schema-response { "type": "object", "properties": { "suggestion": { "type": "string", "description": "Generated reply body as a text string, in the customer's language. It is neither saved nor sent. Review and edit it before presenting or sending it to the customer; treat generated text as untrusted content, not HTML." } }, "required": [ "suggestion" ], "additionalProperties": false, "examples": [ { "suggestion": "You can upload a CSV with a header row and one contact per row. Include name and email columns. If you share the column names you use, I can help you check the mapping before importing." } ] } ``` --- # Add inbox support address Add a support email address to an inbox and send a verification message. Forward that message back to Brigg to verify the address. Adding an existing address sends a new verification message. POST https://api.brigg.app/v1/operations/support.AddInboxSupportAddress ## Access & visibility Allow `support.AddInboxSupportAddress` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `inbox_id` | string | Yes | Use the support inbox record's top-level id, not its slug or forwarding address. [support.ListInboxes](/developers/reference/support/ListInboxes). At least 1 character. | | `address` | string | Yes | Public support email address that you have configured to forward into this inbox. Adding sends a verification email; it does not configure your email provider. At least 3 characters. At most 254 characters. | ## Verify forwarding before using a support address Get the inbox_id and forwarding address from [List inbox channels](/developers/reference/support/ListInboxChannels). Configure your mail provider to forward the public support address into that inbox, then [add the address](/developers/reference/support/AddInboxSupportAddress). Adding it sends a verification email; the address becomes verified only when that email is forwarded back into the correct Brigg inbox. List support addresses to check verified_at. A test=sent response only confirms a send attempt; it is not verification. Only the newest test can verify, and it expires after 24 hours. Fix forwarding before requesting another test. Verification permits that address to be used as Reply-To for its conversations; it does not change the authenticated sender. Removing the address withdraws its verified Reply-To use. It does not remove your mail provider's forwarding rule or delete the inbox and its conversations. Change provider forwarding separately when retiring the address. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `address` | [object](#response-address) | Yes | Street address, including building or unit when applicable. | | `test` | string | Yes | sent means a test email was sent; already_verified sends nothing; rate_limited means wait before requesting another test; send_failed means delivery could not be initiated. Read verified_at to confirm forwarding verification. | ### response.address | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Additional address id from ListInboxSupportAddresses.items for this same inbox_id. It is not the email address, inbox ID, or a verification token. | | `address` | string | Yes | Normalized additional public support email address, distinct from Brigg's generated inbox-forwarding address. | | `created_at` | number | Yes | Unix millisecond timestamp when this address was added. | | `verified_at` | number or null | Yes | Unix millisecond time a valid test returned through this inbox, or null while unverified. | | `test_sent_at` | number or null | Yes | Unix millisecond time the newest test was sent, or null if no test has been sent. This does not prove verification. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 400 | `invalid_address` | Supply a single valid public support email address. | | 400 | `too_many` | The inbox already has the supported twenty additional addresses. Review existing entries before removing any. | | 409 | `org_not_provisioned` | This workspace has no inbox-forwarding configuration yet. Finish inbox setup in Brigg. | ## Next steps - [List inbox support addresses](/developers/reference/support/ListInboxSupportAddresses) - [Resend inbox support address test](/developers/reference/support/ResendInboxSupportAddressTest) - [Remove inbox support address](/developers/reference/support/RemoveInboxSupportAddress) - [List inbox channels](/developers/reference/support/ListInboxChannels) - [List inboxes](/developers/reference/support/ListInboxes) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Add and send the verification email Store address.id and poll ListInboxSupportAddresses for verified_at. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.AddInboxSupportAddress' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "inbox_id": "e_inbox_support", "address": "help@example.com" }' ``` #### TypeScript ```typescript 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/support.AddInboxSupportAddress", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "inbox_id": "e_inbox_support", "address": "help@example.com" }), }); 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 = { "inbox_id": "e_inbox_support", "address": "help@example.com" } request = Request( "https://api.brigg.app/v1/operations/support.AddInboxSupportAddress", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "address": { "id": "isa_help", "address": "help@example.com", "created_at": 1794301200000, "verified_at": null, "test_sent_at": 1794301200000 }, "test": "sent" } ``` ### Address saved but test held Keep the address ID; retry the test later rather than creating another address. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.AddInboxSupportAddress' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "inbox_id": "e_inbox_support", "address": "help@example.com" }' ``` #### TypeScript ```typescript 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/support.AddInboxSupportAddress", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "inbox_id": "e_inbox_support", "address": "help@example.com" }), }); 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 = { "inbox_id": "e_inbox_support", "address": "help@example.com" } request = Request( "https://api.brigg.app/v1/operations/support.AddInboxSupportAddress", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "address": { "id": "isa_help", "address": "help@example.com", "created_at": 1794301200000, "verified_at": null, "test_sent_at": null }, "test": "rate_limited" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "inbox_id": { "type": "string", "minLength": 1, "description": "Use the support inbox record's top-level id, not its slug or forwarding address. [support.ListInboxes](/developers/reference/support/ListInboxes)." }, "address": { "type": "string", "minLength": 3, "maxLength": 254, "description": "Public support email address that you have configured to forward into this inbox. Adding sends a verification email; it does not configure your email provider." } }, "required": [ "inbox_id", "address" ], "additionalProperties": false, "examples": [ { "inbox_id": "e_inbox_support", "address": "help@example.com" } ] } ``` ```json-schema-response { "type": "object", "properties": { "address": { "type": "object", "properties": { "id": { "type": "string", "description": "Additional address id from ListInboxSupportAddresses.items for this same inbox_id. It is not the email address, inbox ID, or a verification token." }, "address": { "type": "string", "description": "Normalized additional public support email address, distinct from Brigg's generated inbox-forwarding address." }, "created_at": { "type": "number", "description": "Unix millisecond timestamp when this address was added." }, "verified_at": { "type": [ "number", "null" ], "description": "Unix millisecond time a valid test returned through this inbox, or null while unverified." }, "test_sent_at": { "type": [ "number", "null" ], "description": "Unix millisecond time the newest test was sent, or null if no test has been sent. This does not prove verification." } }, "required": [ "id", "address", "created_at", "verified_at", "test_sent_at" ], "additionalProperties": false, "description": "Street address, including building or unit when applicable." }, "test": { "type": "string", "description": "sent means a test email was sent; already_verified sends nothing; rate_limited means wait before requesting another test; send_failed means delivery could not be initiated. Read verified_at to confirm forwarding verification." } }, "required": [ "address", "test" ], "additionalProperties": false, "examples": [ { "address": { "id": "isa_help", "address": "help@example.com", "created_at": 1794301200000, "verified_at": null, "test_sent_at": 1794301200000 }, "test": "sent" } ] } ``` --- # Remove inbox support address Remove a support email address from an inbox. Customer replies will no longer use that address. POST https://api.brigg.app/v1/operations/support.RemoveInboxSupportAddress ## Access & visibility Allow `support.RemoveInboxSupportAddress` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `inbox_id` | string | Yes | Use the support inbox record's top-level id, not its slug or forwarding address. [support.ListInboxes](/developers/reference/support/ListInboxes). At least 1 character. | | `id` | string | Yes | Additional address id from ListInboxSupportAddresses.items for this same inbox_id. It is not the email address, inbox ID, or a verification token. At least 1 character. | ## Verify forwarding before using a support address Get the inbox_id and forwarding address from [List inbox channels](/developers/reference/support/ListInboxChannels). Configure your mail provider to forward the public support address into that inbox, then [add the address](/developers/reference/support/AddInboxSupportAddress). Adding it sends a verification email; the address becomes verified only when that email is forwarded back into the correct Brigg inbox. List support addresses to check verifiedAt. A test=sent response only confirms a send attempt; it is not verification. Only the newest test can verify, and it expires after 24 hours. Fix forwarding before requesting another test. Verification permits that address to be used as Reply-To for its conversations; it does not change the authenticated sender. Removing the address withdraws its verified Reply-To use. It does not remove your mail provider's forwarding rule or delete the inbox and its conversations. Change provider forwarding separately when retiring the address. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The inbox or the additional-address ID is absent. Re-list that inbox's support addresses; do not substitute an email string or a different inbox's ID. | | 429 | `rate_limited` | Wait for Retry-After before retrying. Reuse the original Idempotency-Key. | ## Next steps - [List inbox support addresses](/developers/reference/support/ListInboxSupportAddresses) - [Add inbox support address](/developers/reference/support/AddInboxSupportAddress) - [Resend inbox support address test](/developers/reference/support/ResendInboxSupportAddressTest) - [List inbox channels](/developers/reference/support/ListInboxChannels) - [List inboxes](/developers/reference/support/ListInboxes) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Remove one additional address The inbox and its other addresses remain; provider forwarding is managed separately. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.RemoveInboxSupportAddress' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "inbox_id": "e_inbox_support", "id": "isa_help" }' ``` #### TypeScript ```typescript 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/support.RemoveInboxSupportAddress", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "inbox_id": "e_inbox_support", "id": "isa_help" }), }); 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 = { "inbox_id": "e_inbox_support", "id": "isa_help" } request = Request( "https://api.brigg.app/v1/operations/support.RemoveInboxSupportAddress", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "inbox_id": { "type": "string", "minLength": 1, "description": "Use the support inbox record's top-level id, not its slug or forwarding address. [support.ListInboxes](/developers/reference/support/ListInboxes)." }, "id": { "type": "string", "minLength": 1, "description": "Additional address id from ListInboxSupportAddresses.items for this same inbox_id. It is not the email address, inbox ID, or a verification token." } }, "required": [ "inbox_id", "id" ], "additionalProperties": false, "examples": [ { "inbox_id": "e_inbox_support", "id": "isa_help" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." } }, "required": [ "ok" ], "additionalProperties": false, "examples": [ { "ok": true } ] } ``` --- # Resend inbox support address test Resend a verification email for a pending inbox support address. POST https://api.brigg.app/v1/operations/support.ResendInboxSupportAddressTest ## Access & visibility Allow `support.ResendInboxSupportAddressTest` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `inbox_id` | string | Yes | Use the support inbox record's top-level id, not its slug or forwarding address. [support.ListInboxes](/developers/reference/support/ListInboxes). At least 1 character. | | `id` | string | Yes | Additional address id from ListInboxSupportAddresses.items for this same inbox_id. It is not the email address, inbox ID, or a verification token. At least 1 character. | ## Verify forwarding before using a support address Get the inbox_id and forwarding address from [List inbox channels](/developers/reference/support/ListInboxChannels). Configure your mail provider to forward the public support address into that inbox, then [add the address](/developers/reference/support/AddInboxSupportAddress). Adding it sends a verification email; the address becomes verified only when that email is forwarded back into the correct Brigg inbox. List support addresses to check verifiedAt. A test=sent response only confirms a send attempt; it is not verification. Only the newest test can verify, and it expires after 24 hours. Fix forwarding before requesting another test. Verification permits that address to be used as Reply-To for its conversations; it does not change the authenticated sender. Removing the address withdraws its verified Reply-To use. It does not remove your mail provider's forwarding rule or delete the inbox and its conversations. Change provider forwarding separately when retiring the address. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `test` | string | Yes | sent confirms a test email was sent; already_verified sends nothing; send_failed means delivery could not be initiated. Verification still requires the email to return through the inbox. Send throttling is HTTP 429 rate_limited, not a successful test value. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Too many verification sends. Existing limits are ten per inbox and thirty per workspace per hour; wait before a new test action. | | 409 | `org_not_provisioned` | Finish inbox-forwarding setup in Brigg before requesting verification. | ## Next steps - [List inbox support addresses](/developers/reference/support/ListInboxSupportAddresses) - [Add inbox support address](/developers/reference/support/AddInboxSupportAddress) - [Remove inbox support address](/developers/reference/support/RemoveInboxSupportAddress) - [List inbox channels](/developers/reference/support/ListInboxChannels) - [List inboxes](/developers/reference/support/ListInboxes) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Send a fresh test The new test supersedes the previous one; it must return through this same inbox. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/support.ResendInboxSupportAddressTest' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "inbox_id": "e_inbox_support", "id": "isa_help" }' ``` #### TypeScript ```typescript 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/support.ResendInboxSupportAddressTest", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "inbox_id": "e_inbox_support", "id": "isa_help" }), }); 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 = { "inbox_id": "e_inbox_support", "id": "isa_help" } request = Request( "https://api.brigg.app/v1/operations/support.ResendInboxSupportAddressTest", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "test": "sent" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "inbox_id": { "type": "string", "minLength": 1, "description": "Use the support inbox record's top-level id, not its slug or forwarding address. [support.ListInboxes](/developers/reference/support/ListInboxes)." }, "id": { "type": "string", "minLength": 1, "description": "Additional address id from ListInboxSupportAddresses.items for this same inbox_id. It is not the email address, inbox ID, or a verification token." } }, "required": [ "inbox_id", "id" ], "additionalProperties": false, "examples": [ { "inbox_id": "e_inbox_support", "id": "isa_help" } ] } ``` ```json-schema-response { "type": "object", "properties": { "test": { "type": "string", "description": "sent confirms a test email was sent; already_verified sends nothing; send_failed means delivery could not be initiated. Verification still requires the email to return through the inbox. Send throttling is HTTP 429 rate_limited, not a successful test value." } }, "required": [ "test" ], "additionalProperties": false, "examples": [ { "test": "sent" } ] } ``` --- # Add brief context Add a note, website, document or record to a record’s briefing sources in Brigg. Keep the returned source_id for removal; adding the same reference again reuses it. Website content must be fetched before regeneration can start. Review the brief in Brigg; the public record model does not expose its body. POST https://api.brigg.app/v1/operations/customers.AddBriefContext ## Access & visibility Allow `customers.AddBriefContext` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `target` | [object](#request-target) | Yes | The Company, Person or Meeting whose brief receives the context. Use its exact record type and top-level ID. | | `item` | [object (4 variants)](#request-item) | Yes | One source to attach, chosen by kind. Supply the fields for that variant only; this is an input source, not a returned record. | ### request.target | Field | Type | Required | Description | | --- | --- | --- | --- | | `type` | string | Yes | Exact type of the target record: core:Company, core:Person or core:Meeting. At least 1 character. At most 60 characters. | | `id` | string | Yes | Top-level record ID from ListCompanies, ListPeople or ListMeetings matching target.type. At least 1 character. At most 80 characters. | ### request.item #### kind = "note" | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | note supplies text; link supplies an HTTP(S) page URL; file refers to a readable document; entry refers to another readable record. Always `"note"`. | | `text` | string | Yes | Text content. At least 1 character. At most 20000 characters. | #### kind = "link" | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | note supplies text; link supplies an HTTP(S) page URL; file refers to a readable document; entry refers to another readable record. Always `"link"`. | | `url` | string | Yes | An HTTP(S) webpage URL. Its content is fetched asynchronously before use; successful attachment does not mean the fetch succeeded. At least 4 characters. At most 2000 characters. | #### kind = "file" | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | note supplies text; link supplies an HTTP(S) page URL; file refers to a readable document; entry refers to another readable record. Always `"file"`. | | `file_id` | string | Yes | Existing file ID from ListDocuments or CompleteUpload. It must be readable by the target brief's audience. At least 1 character. At most 80 characters. | | `label` | string | No | A label for the row; the filename when omitted. At least 1 character. At most 120 characters. | #### kind = "entry" | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | note supplies text; link supplies an HTTP(S) page URL; file refers to a readable document; entry refers to another readable record. Always `"entry"`. | | `entry_id` | string | Yes | Top-level ID of another visible record. The target brief's audience must be able to read it. At least 1 character. At most 80 characters. | | `meta` | string | No | Optional display subtitle for a referenced record. It does not replace that record's content. At most 160 characters. | ## Choose the record, then manage its briefing sources Use a top-level record ID from [List companies](/developers/reference/customers/ListCompanies), [List people](/developers/reference/customers/ListPeople) or [List meetings](/developers/reference/meetings/ListMeetings), paired with its matching target.type. An account ID cannot identify this target. A new context item or a removal schedules regeneration when the brief is ready to run; the response confirms the context change, not a finished brief. A website first needs its content fetched. [Generate brief](/developers/reference/customers/GenerateBrief) can report scrape_pending or already_running instead of starting more work. Review the resulting brief and source-fetch state in Brigg: the public record model does not expose the brief body or a source-status listing. Keep source_id together with target for removal. It identifies the attachment to this brief, not the original file or record. Adding the same URL, file or record again reuses its source_id; notes are distinct additions. Removing a source leaves the original file or record intact. A file or referenced record must be readable by the target brief's audience, not merely by the caller. Adding a member-private file to a workspace-shared brief is refused. The target's existing private/workspace visibility stays in force. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | The context source is attached. Generation and website fetching may still be pending. | | `source_id` | string | Yes | Identity of this context attachment. Keep it with target to call RemoveBriefContext; it is not the original file or record ID. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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 target is unavailable, or the source file/record is not readable by the target brief's audience. | | 429 | `rate_limited` | Wait for Retry-After before retrying. Reuse the original Idempotency-Key. | | 400 | `bad_url` | Use an HTTP or HTTPS page URL for kind=link. | | 409 | `conflict` | A concurrent context change could not be resolved. Re-read the brief in Brigg before making a new action. | ## Next steps - [List companies](/developers/reference/customers/ListCompanies) - [List people](/developers/reference/customers/ListPeople) - [List meetings](/developers/reference/meetings/ListMeetings) - [Remove brief context](/developers/reference/customers/RemoveBriefContext) - [Generate brief](/developers/reference/customers/GenerateBrief) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Add a written note The source is attached and eligible regeneration is scheduled. This response contains no generated brief. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.AddBriefContext' \ -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 '{ "target": { "type": "core:Company", "id": "e_company_northstar" }, "item": { "kind": "note", "text": "The customer wants a two-week pilot before rollout." } }' ``` #### 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/customers.AddBriefContext", { 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({ "target": { "type": "core:Company", "id": "e_company_northstar" }, "item": { "kind": "note", "text": "The customer wants a two-week pilot before rollout." } }), }); 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 = { "target": { "type": "core:Company", "id": "e_company_northstar" }, "item": { "kind": "note", "text": "The customer wants a two-week pilot before rollout." } } request = Request( "https://api.brigg.app/v1/operations/customers.AddBriefContext", 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, "source_id": "bci_note_northstar" } ``` ### Add a website The source is attached while website fetching continues. Inspect the brief in Brigg before relying on the fetched content. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.AddBriefContext' \ -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 '{ "target": { "type": "core:Company", "id": "e_company_northstar" }, "item": { "kind": "link", "url": "https://example.com/company" } }' ``` #### 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/customers.AddBriefContext", { 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({ "target": { "type": "core:Company", "id": "e_company_northstar" }, "item": { "kind": "link", "url": "https://example.com/company" } }), }); 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 = { "target": { "type": "core:Company", "id": "e_company_northstar" }, "item": { "kind": "link", "url": "https://example.com/company" } } request = Request( "https://api.brigg.app/v1/operations/customers.AddBriefContext", 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, "source_id": "bci_link_northstar" } ``` ### Attach an existing document The source is attached and eligible regeneration is scheduled. This response contains no generated brief. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.AddBriefContext' \ -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 '{ "target": { "type": "core:Company", "id": "e_company_northstar" }, "item": { "kind": "file", "file_id": "f_proposal", "label": "Project proposal" } }' ``` #### 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/customers.AddBriefContext", { 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({ "target": { "type": "core:Company", "id": "e_company_northstar" }, "item": { "kind": "file", "file_id": "f_proposal", "label": "Project proposal" } }), }); 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 = { "target": { "type": "core:Company", "id": "e_company_northstar" }, "item": { "kind": "file", "file_id": "f_proposal", "label": "Project proposal" } } request = Request( "https://api.brigg.app/v1/operations/customers.AddBriefContext", 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, "source_id": "bci_file_northstar" } ``` ### Reference a contact The source is attached and eligible regeneration is scheduled. This response contains no generated brief. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.AddBriefContext' \ -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 '{ "target": { "type": "core:Company", "id": "e_company_northstar" }, "item": { "kind": "entry", "entry_id": "e_person_alex", "meta": "Project sponsor" } }' ``` #### 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/customers.AddBriefContext", { 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({ "target": { "type": "core:Company", "id": "e_company_northstar" }, "item": { "kind": "entry", "entry_id": "e_person_alex", "meta": "Project sponsor" } }), }); 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 = { "target": { "type": "core:Company", "id": "e_company_northstar" }, "item": { "kind": "entry", "entry_id": "e_person_alex", "meta": "Project sponsor" } } request = Request( "https://api.brigg.app/v1/operations/customers.AddBriefContext", 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, "source_id": "bci_entry_northstar" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "target": { "type": "object", "properties": { "type": { "type": "string", "minLength": 1, "maxLength": 60, "description": "Exact type of the target record: core:Company, core:Person or core:Meeting." }, "id": { "type": "string", "minLength": 1, "maxLength": 80, "description": "Top-level record ID from ListCompanies, ListPeople or ListMeetings matching target.type." } }, "required": [ "type", "id" ], "additionalProperties": false, "description": "The Company, Person or Meeting whose brief receives the context. Use its exact record type and top-level ID." }, "item": { "anyOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "note", "description": "note supplies text; link supplies an HTTP(S) page URL; file refers to a readable document; entry refers to another readable record." }, "text": { "type": "string", "minLength": 1, "maxLength": 20000, "description": "Text content." } }, "required": [ "kind", "text" ], "additionalProperties": false, "description": "One source to attach, chosen by kind. Supply the fields for that variant only; this is an input source, not a returned record." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "link", "description": "note supplies text; link supplies an HTTP(S) page URL; file refers to a readable document; entry refers to another readable record." }, "url": { "type": "string", "minLength": 4, "maxLength": 2000, "description": "An HTTP(S) webpage URL. Its content is fetched asynchronously before use; successful attachment does not mean the fetch succeeded." } }, "required": [ "kind", "url" ], "additionalProperties": false, "description": "One source to attach, chosen by kind. Supply the fields for that variant only; this is an input source, not a returned record." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "file", "description": "note supplies text; link supplies an HTTP(S) page URL; file refers to a readable document; entry refers to another readable record." }, "file_id": { "type": "string", "minLength": 1, "maxLength": 80, "description": "Existing file ID from ListDocuments or CompleteUpload. It must be readable by the target brief's audience." }, "label": { "type": "string", "minLength": 1, "maxLength": 120, "description": "A label for the row; the filename when omitted." } }, "required": [ "kind", "file_id" ], "additionalProperties": false, "description": "One source to attach, chosen by kind. Supply the fields for that variant only; this is an input source, not a returned record." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "entry", "description": "note supplies text; link supplies an HTTP(S) page URL; file refers to a readable document; entry refers to another readable record." }, "entry_id": { "type": "string", "minLength": 1, "maxLength": 80, "description": "Top-level ID of another visible record. The target brief's audience must be able to read it." }, "meta": { "type": "string", "maxLength": 160, "description": "Optional display subtitle for a referenced record. It does not replace that record's content." } }, "required": [ "kind", "entry_id" ], "additionalProperties": false, "description": "One source to attach, chosen by kind. Supply the fields for that variant only; this is an input source, not a returned record." } ], "description": "One source to attach, chosen by kind. Supply the fields for that variant only; this is an input source, not a returned record." } }, "required": [ "target", "item" ], "additionalProperties": false, "examples": [ { "target": { "type": "core:Company", "id": "e_company_northstar" }, "item": { "kind": "note", "text": "The customer wants a two-week pilot before rollout." } } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "The context source is attached. Generation and website fetching may still be pending." }, "source_id": { "type": "string", "description": "Identity of this context attachment. Keep it with target to call RemoveBriefContext; it is not the original file or record ID." } }, "required": [ "ok", "source_id" ], "additionalProperties": false, "examples": [ { "ok": true, "source_id": "bci_note_northstar" } ] } ``` --- # Generate brief Generate or refresh a record’s brief in Brigg. A current brief is reused unless force is true. When work starts, poll workspace.GetJob using job_id. The public API returns progress and the affected record ID; the brief body is reviewed in Brigg and is not included in the public record model. POST https://api.brigg.app/v1/operations/customers.GenerateBrief ## Access & visibility Allow `customers.GenerateBrief` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `target` | [object](#request-target) | Yes | The record or content item to which this operation applies. | | `force` | boolean | No | Regenerate a fresh brief. Omit or send false to reuse it. Other readiness, permission and credit checks still apply. | ### request.target | Field | Type | Required | Description | | --- | --- | --- | --- | | `type` | string | Yes | The record's type: core:Meeting, core:Company or core:Person. At least 1 character. At most 60 characters. | | `id` | string | Yes | Visible Company, Person or Meeting record ID. Match it to target.type; an account ID cannot be used here. At least 1 character. At most 80 characters. | ## Start, wait, then review 1. Find the target with [List companies](/developers/reference/customers/ListCompanies), [List people](/developers/reference/customers/ListPeople) or [List meetings](/developers/reference/meetings/ListMeetings). Pass its resource type and record ID together. 2. Call this operation. `started: true` means work was queued, not that the brief is ready. Keep the returned `job_id`. 3. Poll [Get job](/developers/reference/workspace/GetJob) with the same acting member until it completes, fails or needs input. Respect `retry_at` when supplied. 4. Review the brief on that record in Brigg. The current public record models do **not** expose the brief body; the job result identifies the affected record, not the generated text. Use this operation to refresh Brigg's briefing, not to obtain generated prose for another system. ## When no job starts `fresh` means the existing brief can be reused. `already_running` means another run is working on this target; this response does not include that run's job ID. `scrape_pending` waits for linked website content. `awaiting_first_prep` waits for the meeting's initial preparation. `no_target` means the target disappeared or is no longer available. Other reasons can be returned; retain the reason for diagnostics instead of assuming every no-op means success. `force: true` bypasses the freshness check only. It does not bypass an active run, pending source material, access checks or credit checks. Starting generation uses workspace credits; reusing a fresh brief starts no new generation. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | | `started` | boolean | Yes | True when new background work started. False requires inspecting reason; neither value means generation has completed. | | `reason` | string | No | Why no new work started, for example fresh, already_running, scrape_pending or awaiting_first_prep. Treat this as an open set of outcomes. | | `job_id` | string | No | Present when new work starts. Poll [Get job](/developers/reference/workspace/GetJob) as the same member. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | ## Next steps - [Get job](/developers/reference/workspace/GetJob) - [Add brief context](/developers/reference/customers/AddBriefContext) - [Remove brief context](/developers/reference/customers/RemoveBriefContext) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Start a refresh A stale brief starts a background job. The ID is fictional; use the ID your response returns. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.GenerateBrief' \ -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 '{ "target": { "type": "core:Company", "id": "e_company_northstar" } }' ``` #### 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/customers.GenerateBrief", { 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({ "target": { "type": "core:Company", "id": "e_company_northstar" } }), }); 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 = { "target": { "type": "core:Company", "id": "e_company_northstar" } } request = Request( "https://api.brigg.app/v1/operations/customers.GenerateBrief", 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, "started": true, "job_id": "job_brief_northstar" } ``` ### Reuse a current brief The same request can return a no-op. There is no job to poll in this response. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.GenerateBrief' \ -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 '{ "target": { "type": "core:Company", "id": "e_company_northstar" } }' ``` #### 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/customers.GenerateBrief", { 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({ "target": { "type": "core:Company", "id": "e_company_northstar" } }), }); 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 = { "target": { "type": "core:Company", "id": "e_company_northstar" } } request = Request( "https://api.brigg.app/v1/operations/customers.GenerateBrief", 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, "started": false, "reason": "fresh" } ``` ### Refresh despite a current brief This can incur another generation charge. It still cannot start a duplicate active run. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.GenerateBrief' \ -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 '{ "target": { "type": "core:Company", "id": "e_company_northstar" }, "force": true }' ``` #### 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/customers.GenerateBrief", { 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({ "target": { "type": "core:Company", "id": "e_company_northstar" }, "force": true }), }); 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 = { "target": { "type": "core:Company", "id": "e_company_northstar" }, "force": True } request = Request( "https://api.brigg.app/v1/operations/customers.GenerateBrief", 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, "started": false, "reason": "already_running" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "target": { "type": "object", "properties": { "type": { "type": "string", "minLength": 1, "maxLength": 60, "description": "The record's type: core:Meeting, core:Company or core:Person." }, "id": { "type": "string", "minLength": 1, "maxLength": 80, "description": "Visible Company, Person or Meeting record ID. Match it to target.type; an account ID cannot be used here." } }, "required": [ "type", "id" ], "additionalProperties": false, "description": "The record or content item to which this operation applies." }, "force": { "type": "boolean", "description": "Regenerate a fresh brief. Omit or send false to reuse it. Other readiness, permission and credit checks still apply." } }, "required": [ "target" ], "additionalProperties": false, "examples": [ { "target": { "type": "core:Company", "id": "e_company_northstar" } } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." }, "started": { "type": "boolean", "description": "True when new background work started. False requires inspecting reason; neither value means generation has completed." }, "reason": { "type": "string", "description": "Why no new work started, for example fresh, already_running, scrape_pending or awaiting_first_prep. Treat this as an open set of outcomes." }, "job_id": { "type": "string", "description": "Present when new work starts. Poll [Get job](/developers/reference/workspace/GetJob) as the same member." } }, "required": [ "ok", "started" ], "additionalProperties": false, "examples": [ { "ok": true, "started": true, "job_id": "job_brief_northstar" } ] } ``` --- # Remove brief context Remove a briefing source using the source_id returned when it was added and request regeneration without it. This confirms source removal, not completed generation. Review the updated brief in Brigg; the public record model does not expose its body. POST https://api.brigg.app/v1/operations/customers.RemoveBriefContext ## Access & visibility Allow `customers.RemoveBriefContext` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `target` | [object](#request-target) | Yes | The Company, Person or Meeting whose brief receives the context. Use its exact record type and top-level ID. | | `source_id` | string | Yes | source_id previously returned by AddBriefContext for this same target. It is not the source file's ID or an array position. At least 1 character. At most 80 characters. | ### request.target | Field | Type | Required | Description | | --- | --- | --- | --- | | `type` | string | Yes | Exact type of the target record: core:Company, core:Person or core:Meeting. At least 1 character. At most 60 characters. | | `id` | string | Yes | Top-level record ID from ListCompanies, ListPeople or ListMeetings matching target.type. At least 1 character. At most 80 characters. | ## Choose the record, then manage its briefing sources Use a top-level record ID from [List companies](/developers/reference/customers/ListCompanies), [List people](/developers/reference/customers/ListPeople) or [List meetings](/developers/reference/meetings/ListMeetings), paired with its matching target.type. An account ID cannot identify this target. A new context item or a removal schedules regeneration when the brief is ready to run; the response confirms the context change, not a finished brief. A website first needs its content fetched. [Generate brief](/developers/reference/customers/GenerateBrief) can report scrape_pending or already_running instead of starting more work. Review the resulting brief and source-fetch state in Brigg: the public record model does not expose the brief body or a source-status listing. Keep source_id together with target for removal. It identifies the attachment to this brief, not the original file or record. Adding the same URL, file or record again reuses its source_id; notes are distinct additions. Removing a source leaves the original file or record intact. A file or referenced record must be readable by the target brief's audience, not merely by the caller. Adding a member-private file to a workspace-shared brief is refused. The target's existing private/workspace visibility stays in force. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | The source was removed from this brief and eligible regeneration was scheduled. The original file or record remains. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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 target or source attachment is unavailable. Use the saved source_id with its original target; removing the original file is a different action. | | 429 | `rate_limited` | Wait for Retry-After before retrying. Reuse the original Idempotency-Key. | ## Next steps - [List companies](/developers/reference/customers/ListCompanies) - [List people](/developers/reference/customers/ListPeople) - [List meetings](/developers/reference/meetings/ListMeetings) - [Add brief context](/developers/reference/customers/AddBriefContext) - [Generate brief](/developers/reference/customers/GenerateBrief) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Remove one briefing source Use the saved attachment ID and its original target. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.RemoveBriefContext' \ -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 '{ "target": { "type": "core:Company", "id": "e_company_northstar" }, "source_id": "bci_note_northstar" }' ``` #### 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/customers.RemoveBriefContext", { 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({ "target": { "type": "core:Company", "id": "e_company_northstar" }, "source_id": "bci_note_northstar" }), }); 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 = { "target": { "type": "core:Company", "id": "e_company_northstar" }, "source_id": "bci_note_northstar" } request = Request( "https://api.brigg.app/v1/operations/customers.RemoveBriefContext", 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 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "target": { "type": "object", "properties": { "type": { "type": "string", "minLength": 1, "maxLength": 60, "description": "Exact type of the target record: core:Company, core:Person or core:Meeting." }, "id": { "type": "string", "minLength": 1, "maxLength": 80, "description": "Top-level record ID from ListCompanies, ListPeople or ListMeetings matching target.type." } }, "required": [ "type", "id" ], "additionalProperties": false, "description": "The Company, Person or Meeting whose brief receives the context. Use its exact record type and top-level ID." }, "source_id": { "type": "string", "minLength": 1, "maxLength": 80, "description": "source_id previously returned by AddBriefContext for this same target. It is not the source file's ID or an array position." } }, "required": [ "target", "source_id" ], "additionalProperties": false, "examples": [ { "target": { "type": "core:Company", "id": "e_company_northstar" }, "source_id": "bci_note_northstar" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "The source was removed from this brief and eligible regeneration was scheduled. The original file or record remains." } }, "required": [ "ok" ], "additionalProperties": false, "examples": [ { "ok": true } ] } ``` --- # Run brief action Start a known task or chat recommendation from an existing brief. Tasks return a private job to poll; chat actions continue in the acting member’s Brigg conversation. The public API does not list recommendation IDs. POST https://api.brigg.app/v1/operations/customers.RunBriefAction ## Access & visibility Allow `customers.RunBriefAction` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `target` | [object](#request-target) | Yes | Record whose existing brief contains the selected action. Pair its exact type and record ID. | | `action_id` | string | Yes | ID of an existing task or chat recommendation in this record’s brief. It is not the target record ID, a job ID, or a caller-created instruction. At least 1 character. At most 80 characters. | ### request.target | Field | Type | Required | Description | | --- | --- | --- | --- | | `type` | string | Yes | The record's type: core:Meeting, core:Company or core:Person. At least 1 character. At most 60 characters. | | `id` | string | Yes | The record's entry id. At least 1 character. At most 80 characters. | ## Use an existing recommendation, then follow its outcome This operation executes an action already present on a Company, Person or Meeting brief. It does not create an arbitrary agent task. The public API does not enumerate brief action IDs or return the brief body. If you do not already have the action_id from an existing Brigg workflow, use the brief in Brigg instead of inventing an ID. Regenerating the brief can replace its recommendations. A task action returns job_id: poll [Get job](/developers/reference/workspace/GetJob), keeping the same approved member. A chat action returns chat: true and posts to that member’s own agent conversation; follow the conversation in Brigg. Neither response means the agent has finished. Email recommendations must be reviewed in Brigg’s composer and are refused here. Reuse the original idempotency key after a lost response. A new call cannot rerun an already completed task action or repost an already sent chat recommendation. Work waiting for human input must be continued in Brigg; polling does not answer that question. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | The task was accepted or the chat message was posted. This does not mean the requested background work has completed. | | `job_id` | string | No | Present for a task action. Poll workspace.GetJob with the same acting member; results and progress belong to that member. | | `chat` | boolean | No | True for a chat action posted to the acting member’s own conversation. No job_id is returned for this branch; continue in Brigg. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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 target, brief or action is unavailable. Use an action that still belongs to this record’s current brief. | | 429 | `rate_limited` | Wait for Retry-After before retrying. Reuse the original Idempotency-Key. | | 400 | `not_runnable` | Email recommendations require review in Brigg’s composer; this endpoint runs task and chat actions only. | | 409 | `already_done` | This task recommendation already completed. Review its existing result rather than starting it again. | | 409 | `already_sent` | This chat recommendation was already posted. Continue that conversation in Brigg. | ## Next steps - [Get job](/developers/reference/workspace/GetJob) - [Generate brief](/developers/reference/customers/GenerateBrief) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Start a known task recommendation The action ID already belongs to this company’s brief. Keep the returned job ID for polling. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.RunBriefAction' \ -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 '{ "target": { "type": "core:Company", "id": "e_company_northstar" }, "action_id": "action_prepare_proposal" }' ``` #### 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/customers.RunBriefAction", { 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({ "target": { "type": "core:Company", "id": "e_company_northstar" }, "action_id": "action_prepare_proposal" }), }); 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 = { "target": { "type": "core:Company", "id": "e_company_northstar" }, "action_id": "action_prepare_proposal" } request = Request( "https://api.brigg.app/v1/operations/customers.RunBriefAction", 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, "job_id": "job_prepare_proposal" } ``` ### Continue a known recommendation in chat The message is posted to the acting member’s own conversation; there is no job ID to poll. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.RunBriefAction' \ -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 '{ "target": { "type": "core:Company", "id": "e_company_northstar" }, "action_id": "action_discuss_proposal" }' ``` #### 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/customers.RunBriefAction", { 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({ "target": { "type": "core:Company", "id": "e_company_northstar" }, "action_id": "action_discuss_proposal" }), }); 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 = { "target": { "type": "core:Company", "id": "e_company_northstar" }, "action_id": "action_discuss_proposal" } request = Request( "https://api.brigg.app/v1/operations/customers.RunBriefAction", 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, "chat": true } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "target": { "type": "object", "properties": { "type": { "type": "string", "minLength": 1, "maxLength": 60, "description": "The record's type: core:Meeting, core:Company or core:Person." }, "id": { "type": "string", "minLength": 1, "maxLength": 80, "description": "The record's entry id." } }, "required": [ "type", "id" ], "additionalProperties": false, "description": "Record whose existing brief contains the selected action. Pair its exact type and record ID." }, "action_id": { "type": "string", "minLength": 1, "maxLength": 80, "description": "ID of an existing task or chat recommendation in this record’s brief. It is not the target record ID, a job ID, or a caller-created instruction." } }, "required": [ "target", "action_id" ], "additionalProperties": false, "examples": [ { "target": { "type": "core:Company", "id": "e_company_northstar" }, "action_id": "action_prepare_proposal" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "The task was accepted or the chat message was posted. This does not mean the requested background work has completed." }, "job_id": { "type": "string", "description": "Present for a task action. Poll workspace.GetJob with the same acting member; results and progress belong to that member." }, "chat": { "type": "boolean", "description": "True for a chat action posted to the acting member’s own conversation. No job_id is returned for this branch; continue in Brigg." } }, "required": [ "ok" ], "additionalProperties": false, "examples": [ { "ok": true, "job_id": "job_prepare_proposal" } ] } ``` --- # Get company Read a company by ID. Returns item: null when no visible record matches. POST https://api.brigg.app/v1/operations/customers.GetCompany ## Access & visibility Allow `customers.GetCompany` on your API key. Resource read permissions: `core:Company`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies). Use the record's top-level `id`, not a business field or account ID. | ## Response Returns **200 OK** with a JSON body. `item: null` means there is no matching record visible to this caller. It does not reveal whether an inaccessible record exists. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [CompanyRecord](#companyrecord-response-item) or null | Yes | null when no such record | ### CompanyRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Company record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Company](#company-response-item-data) | Yes | The record's fields. | ### Company · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Company's display name; use org_number and registry_country for its registered identity. | | `domain` | string | No | Website hostname, without a scheme or path. | | `industry` | string | No | Industry classification. Send the stored enum value; the English label is for display only. Values: `bygg` — Construction; `handel` — Retail and wholesale; `konsulent` — Consulting; `it` — Information technology; `helse` — Healthcare; `restaurant` — Restaurants; `eiendom` — Real estate; `transport` — Transport; `finans` — Finance; `utdanning` — Education; `industri` — Manufacturing; `offentlig` — Public sector; `annet` — Other. | | `description` | string | No | Business description recorded for this company. | | `owner_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `website` | string | No | Company website URL, including https://. | | `org_number` | string | No | Organisation number from the company register, stored as text to preserve leading zeros. | | `registry_country` | string | No | Country of registration: NO for Norway or SE for Sweden. Allowed: `"NO"`, `"SE"`. | | `address` | string | No | Street address, including building or unit when applicable. | | `postal_code` | string | No | Postal code as text, preserving leading zeros. | | `city` | string | No | Postal town or city. | | `country` | string | No | Country associated with the address or record. | | `phone` | string | No | Phone number including its country calling code. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | | `product_lines` | array of [object](#response-item-data-product-lines) | No | Products or services agreed with this company, including quantity, price and billing frequency. | | `profile` | [object](#response-item-data-profile) | No | Generated or supplied company profile, with a summary and key facts. | ### response.item.data.product_lines[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `product_ref` | string | No | Product record ID. | | `name` | string | Yes | Display name. | | `description` | string | No | Descriptive text. | | `quantity` | number | No | Number of units. May be fractional when the product allows it. Minimum: 0. | | `unit` | string | No | Unit used for the quantity, such as hours or items. | | `unit_price_ore` | integer | No | Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only. | | `agreed_at` | number | No | Time the commercial terms were agreed, in Unix milliseconds. | | `agreed_deal_ref` | string | No | Deal record ID. | | `revenue_type` | string | No | Whether this amount is charged once or repeats monthly, quarterly or annually. Allowed: `"one_time"`, `"monthly"`, `"quarterly"`, `"annual"`. | | `start_date` | string | No | ISO date (YYYY-MM-DD) | | `end_date` | string | No | ISO date (YYYY-MM-DD) | ### response.item.data.profile | Field | Type | Required | Description | | --- | --- | --- | --- | | `summary` | string | No | Short summary of the source information. | | `highlights` | array of string | No | Key points extracted from the source information. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [List companies](/developers/reference/customers/ListCompanies) - [Create company](/developers/reference/customers/CreateCompany) - [Upsert company](/developers/reference/customers/UpsertCompany) - [Update company](/developers/reference/customers/UpdateCompany) - [Delete company](/developers/reference/customers/DeleteCompany) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.GetCompany' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "e_company_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.GetCompany", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "id": "e_company_example" }), }); 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 payload = { "id": "e_company_example" } request = Request( "https://api.brigg.app/v1/operations/customers.GetCompany", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "item": { "id": "e_company_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "name": "Example Consulting", "industry": "konsulent", "website": "https://example.com", "city": "Oslo" } } } ``` ### No visible record A missing or inaccessible record returns item: null. Do not treat this as proof that a record exists for another member. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.GetCompany' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "e_company_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.GetCompany", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "id": "e_company_example" }), }); 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 payload = { "id": "e_company_example" } request = Request( "https://api.brigg.app/v1/operations/customers.GetCompany", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "item": null } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies). Use the record's top-level `id`, not a business field or account ID." } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_company_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": [ "object", "null" ], "properties": { "id": { "type": "string", "description": "Stable core:Company record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "name": { "type": "string", "description": "Company's display name; use org_number and registry_country for its registered identity." }, "domain": { "type": "string", "description": "Website hostname, without a scheme or path." }, "industry": { "type": "string", "enum": [ "bygg", "handel", "konsulent", "it", "helse", "restaurant", "eiendom", "transport", "finans", "utdanning", "industri", "offentlig", "annet" ], "description": "Industry classification. Send the stored enum value; the English label is for display only. Values: `bygg` — Construction; `handel` — Retail and wholesale; `konsulent` — Consulting; `it` — Information technology; `helse` — Healthcare; `restaurant` — Restaurants; `eiendom` — Real estate; `transport` — Transport; `finans` — Finance; `utdanning` — Education; `industri` — Manufacturing; `offentlig` — Public sector; `annet` — Other." }, "description": { "type": "string", "description": "Business description recorded for this company." }, "owner_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "website": { "type": "string", "description": "Company website URL, including https://." }, "org_number": { "type": "string", "description": "Organisation number from the company register, stored as text to preserve leading zeros." }, "registry_country": { "type": "string", "enum": [ "NO", "SE" ], "description": "Country of registration: NO for Norway or SE for Sweden." }, "address": { "type": "string", "description": "Street address, including building or unit when applicable." }, "postal_code": { "type": "string", "description": "Postal code as text, preserving leading zeros." }, "city": { "type": "string", "description": "Postal town or city." }, "country": { "type": "string", "description": "Country associated with the address or record." }, "phone": { "type": "string", "description": "Phone number including its country calling code." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, "product_lines": { "type": "array", "items": { "type": "object", "properties": { "product_ref": { "type": "string", "description": "Product record ID." }, "name": { "type": "string", "description": "Display name." }, "description": { "type": "string", "description": "Descriptive text." }, "quantity": { "type": "number", "minimum": 0, "description": "Number of units. May be fractional when the product allows it." }, "unit": { "type": "string", "description": "Unit used for the quantity, such as hours or items." }, "unit_price_ore": { "type": "integer", "description": "Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only." }, "agreed_at": { "type": "number", "description": "Time the commercial terms were agreed, in Unix milliseconds." }, "agreed_deal_ref": { "type": "string", "description": "Deal record ID." }, "revenue_type": { "type": "string", "enum": [ "one_time", "monthly", "quarterly", "annual" ], "description": "Whether this amount is charged once or repeats monthly, quarterly or annually." }, "start_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" }, "end_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" } }, "required": [ "name" ], "additionalProperties": false }, "description": "Products or services agreed with this company, including quantity, price and billing frequency." }, "profile": { "type": "object", "properties": { "summary": { "type": "string", "description": "Short summary of the source information." }, "highlights": { "type": "array", "items": { "type": "string" }, "description": "Key points extracted from the source information." } }, "additionalProperties": false, "description": "Generated or supplied company profile, with a summary and key facts." } }, "required": [ "name" ], "additionalProperties": false, "description": "The record's fields.", "title": "Company" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "null when no such record", "title": "CompanyRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_company_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "name": "Example Consulting", "industry": "konsulent", "website": "https://example.com", "city": "Oslo" } } } ] } ``` --- # Get company registry facts Read company-register facts for a customer with an organisation number. Returns facts: null when no matching registry record exists. An unavailable register returns an error instead. POST https://api.brigg.app/v1/operations/customers.GetCompanyRegistryFacts ## Access & visibility Allow `customers.GetCompanyRegistryFacts` on your API key. Resource read permissions: `core:Company`. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | The core:Company record. At least 1 character. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `facts` | null or [object](#getcompanyregistryfactsfacts-response-facts) | Yes | Company-register facts, or null when no matching register record exists. | ### GetCompanyRegistryFactsFacts · response.facts | Field | Type | Required | Description | | --- | --- | --- | --- | | `org_number` | string | Yes | Official organization number as text; preserve leading zeros. | | `employees` | null or number | Yes | Employee count reported by the source. | | `city` | null or string | Yes | Postal town or city. | | `founded_date` | null or string | Yes | Company founding date from the register. | | `status_flag` | null or string | Yes | Company status reported by the register. | | `financials` | null or [object](#response-facts-financials) | Yes | Financial reports returned for this company. | ### response.facts.financials | Field | Type | Required | Description | | --- | --- | --- | --- | | `fiscal_year` | number | Yes | Fiscal year to which these financial figures apply. | | `revenue` | null or number | Yes | Revenue in the source financial report's units. | | `net_result` | null or number | Yes | Net profit or loss in the source financial report's units. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 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. | ## Next steps [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.GetCompanyRegistryFacts' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Brigg-Act-As: $BRIGG_ACT_AS" \ --data-raw '{ "id": "e_example" }' ``` #### 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 response = await fetch("https://api.brigg.app/v1/operations/customers.GetCompanyRegistryFacts", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Brigg-Act-As": actAs, }, body: JSON.stringify({ "id": "e_example" }), }); 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 payload = { "id": "e_example" } request = Request( "https://api.brigg.app/v1/operations/customers.GetCompanyRegistryFacts", 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"], }, 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 { "facts": null } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "The core:Company record." } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "facts": { "description": "Company-register facts, or null when no matching register record exists.", "title": "GetCompanyRegistryFactsFacts", "anyOf": [ { "type": "null" }, { "type": "object", "properties": { "org_number": { "type": "string", "description": "Official organization number as text; preserve leading zeros." }, "employees": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Employee count reported by the source." }, "city": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Postal town or city." }, "founded_date": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Company founding date from the register." }, "status_flag": { "anyOf": [ { "type": "null" }, { "type": "string", "const": "bankrupt" }, { "type": "string", "const": "winding_down" }, { "type": "string", "const": "forced_liquidation" }, { "type": "string", "const": "deleted" } ], "description": "Company status reported by the register." }, "financials": { "anyOf": [ { "type": "null" }, { "type": "object", "properties": { "fiscal_year": { "type": "number", "description": "Fiscal year to which these financial figures apply." }, "revenue": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Revenue in the source financial report's units." }, "net_result": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Net profit or loss in the source financial report's units." } }, "required": [ "fiscal_year", "revenue", "net_result" ], "additionalProperties": false } ], "description": "Financial reports returned for this company." } }, "required": [ "org_number", "employees", "city", "founded_date", "status_flag", "financials" ], "additionalProperties": false } ] } }, "required": [ "facts" ], "additionalProperties": false, "examples": [ { "facts": null } ] } ``` --- # List companies List companies visible to the credential, with filtering, sorting and cursor pagination. POST https://api.brigg.app/v1/operations/customers.ListCompanies ## Access & visibility Allow `customers.ListCompanies` on your API key. Resource read permissions: `core:Company`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `filters` | array of [object](#request-filters) | No | Conditions the row must ALL satisfy. | | `sort` | [object](#request-sort) | No | Sort order for the results. Defaults to updated_at descending, with id as a tie-breaker. | | `limit` | integer | No | Maximum number of results to return in this page. Continue with next_cursor when returned. Default: `100`. Minimum: 1. | | `cursor` | string | No | The `next_cursor` of the previous page. | ### request.filters[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | `data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private. Allowed: `"id"`, `"created_at"`, `"updated_at"`, `"created_by"`, `"private"`, `"data.name"`, `"data.domain"`, `"data.industry"`, `"data.description"`, `"data.owner_ref"`, `"data.website"`, `"data.org_number"`, `"data.registry_country"`, `"data.address"`, `"data.postal_code"`, `"data.city"`, `"data.country"`, `"data.phone"`, `"data.tags"`, `"data.product_lines"`, `"data.profile"`. | | `op` | string | Yes | Comparison operator. Use in with an array, or omit value for is_empty and is_not_empty. Allowed: `"eq"`, `"neq"`, `"contains"`, `"starts_with"`, `"gt"`, `"gte"`, `"lt"`, `"lte"`, `"in"`, `"has"`, `"is_empty"`, `"is_not_empty"`. | | `value` | JSON value | No | The comparison value; an array for `in`; omitted for is_empty / is_not_empty. | ### request.sort | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | `data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private. Allowed: `"id"`, `"created_at"`, `"updated_at"`, `"created_by"`, `"private"`, `"data.name"`, `"data.domain"`, `"data.industry"`, `"data.description"`, `"data.owner_ref"`, `"data.website"`, `"data.org_number"`, `"data.registry_country"`, `"data.address"`, `"data.postal_code"`, `"data.city"`, `"data.country"`, `"data.phone"`, `"data.tags"`, `"data.product_lines"`, `"data.profile"`. | | `direction` | string | No | Sort direction: asc for ascending or desc for descending. Allowed: `"asc"`, `"desc"`. | ## Filtering and sorting All conditions are combined with **AND**. Address business fields as `data.`, and record metadata as `id`, `created_at`, `updated_at`, `created_by` or `private`. A field path names one field; it does not traverse nested objects. | Operator | Meaning | Value | | --- | --- | --- | | `eq` | Equal to a scalar | String, number, boolean or null | | `neq` | Not equal; missing values also match | String, number, boolean or null | | `contains` | Case-insensitive text contains | String; % and _ are literal characters | | `starts_with` | Case-insensitive text prefix | String | | `gt`, `gte` | Greater than / at least | Number or string appropriate to the field | | `lt`, `lte` | Less than / at most | Number or string appropriate to the field | | `in` | Equal to any supplied scalar | Nonempty array of strings, numbers, booleans or null | | `has` | Array contains a string | One string; does not match properties inside array objects | | `is_empty` | Missing, null, empty string or empty array | Omit value | | `is_not_empty` | Has a nonempty value | Omit value | Match the stored field's type. Numeric business timestamps take Unix milliseconds; date-only business fields take `YYYY-MM-DD`. The record metadata fields `created_at` and `updated_at` also accept ISO timestamps for ordered comparisons. Sorting defaults to `updated_at` descending. If you supply `sort.field` without `sort.direction`, direction is `desc`. The record ID breaks ties; missing values sort last. ## Response Returns **200 OK** with a JSON body. An empty `items` array means this page contains no matching visible results. Follow `next_cursor` when present. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [CompanyRecord](#companyrecord-response-items) | Yes | Records visible under the credential's grants and the selected data scope, matching the requested filters. Pass next_cursor as cursor to continue when a next cursor is returned. | | `next_cursor` | string | No | Pass this value as cursor to continue with the same filters, sort and credential. Omitted when there are no more results. | ### CompanyRecord · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Company record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Company](#company-response-items-data) | Yes | The record's fields. | ### Company · response.items[].data | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Company's display name; use org_number and registry_country for its registered identity. | | `domain` | string | No | Website hostname, without a scheme or path. | | `industry` | string | No | Industry classification. Send the stored enum value; the English label is for display only. Values: `bygg` — Construction; `handel` — Retail and wholesale; `konsulent` — Consulting; `it` — Information technology; `helse` — Healthcare; `restaurant` — Restaurants; `eiendom` — Real estate; `transport` — Transport; `finans` — Finance; `utdanning` — Education; `industri` — Manufacturing; `offentlig` — Public sector; `annet` — Other. | | `description` | string | No | Business description recorded for this company. | | `owner_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `website` | string | No | Company website URL, including https://. | | `org_number` | string | No | Organisation number from the company register, stored as text to preserve leading zeros. | | `registry_country` | string | No | Country of registration: NO for Norway or SE for Sweden. Allowed: `"NO"`, `"SE"`. | | `address` | string | No | Street address, including building or unit when applicable. | | `postal_code` | string | No | Postal code as text, preserving leading zeros. | | `city` | string | No | Postal town or city. | | `country` | string | No | Country associated with the address or record. | | `phone` | string | No | Phone number including its country calling code. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | | `product_lines` | array of [object](#response-items-data-product-lines) | No | Products or services agreed with this company, including quantity, price and billing frequency. | | `profile` | [object](#response-items-data-profile) | No | Generated or supplied company profile, with a summary and key facts. | ### response.items[].data.product_lines[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `product_ref` | string | No | Product record ID. | | `name` | string | Yes | Display name. | | `description` | string | No | Descriptive text. | | `quantity` | number | No | Number of units. May be fractional when the product allows it. Minimum: 0. | | `unit` | string | No | Unit used for the quantity, such as hours or items. | | `unit_price_ore` | integer | No | Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only. | | `agreed_at` | number | No | Time the commercial terms were agreed, in Unix milliseconds. | | `agreed_deal_ref` | string | No | Deal record ID. | | `revenue_type` | string | No | Whether this amount is charged once or repeats monthly, quarterly or annually. Allowed: `"one_time"`, `"monthly"`, `"quarterly"`, `"annual"`. | | `start_date` | string | No | ISO date (YYYY-MM-DD) | | `end_date` | string | No | ISO date (YYYY-MM-DD) | ### response.items[].data.profile | Field | Type | Required | Description | | --- | --- | --- | --- | | `summary` | string | No | Short summary of the source information. | | `highlights` | array of string | No | Key points extracted from the source information. | ## Pagination Pass `next_cursor` from the response as `cursor` on the next request. Keep the same filters, sort and acting identity. Stop when `next_cursor` is absent; do not infer completion from the number of items. The default page size is **100**; `limit` must be a positive integer. **Pagination is a live view, not a snapshot.** Changes between pages can move records across page boundaries. Upsert by record ID rather than appending blindly. For recurring synchronization, use an overlapping update window and deduplicate records. Periodically reconcile IDs to detect deletions. [Resource webhooks](/developers/webhooks) can supplement synchronization for eligible workspace-shared records only: they do not export private or project-scoped records. Personal data still needs polling and reconciliation. ```typescript const query = { "filters": [ { "field": "data.industry", "op": "eq", "value": "konsulent" } ], "sort": { "field": "data.name", "direction": "asc" }, "limit": 10 }; let cursor; do { const response = await fetch("https://api.brigg.app/v1/operations/customers.ListCompanies", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ ...query, ...(cursor ? { cursor } : {}) }), }); const page = await response.json(); if (!response.ok) throw new Error(`${response.status}: ${page.message}`); for (const item of page.items) { console.log(item); // Process or upsert each result. } cursor = page.next_cursor; } while (cursor); ``` ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | | 400 | `cursor_invalid` | Restart pagination with no cursor. | | 400 | `cursor_mismatch` | Use the cursor with the original filters, sort order and credential. | ## Next steps - [Get company](/developers/reference/customers/GetCompany) - [Create company](/developers/reference/customers/CreateCompany) - [Upsert company](/developers/reference/customers/UpsertCompany) - [Update company](/developers/reference/customers/UpdateCompany) - [Delete company](/developers/reference/customers/DeleteCompany) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### First page Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.ListCompanies' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "filters": [ { "field": "data.industry", "op": "eq", "value": "konsulent" } ], "sort": { "field": "data.name", "direction": "asc" }, "limit": 10 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.ListCompanies", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "filters": [ { "field": "data.industry", "op": "eq", "value": "konsulent" } ], "sort": { "field": "data.name", "direction": "asc" }, "limit": 10 }), }); 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 payload = { "filters": [ { "field": "data.industry", "op": "eq", "value": "konsulent" } ], "sort": { "field": "data.name", "direction": "asc" }, "limit": 10 } request = Request( "https://api.brigg.app/v1/operations/customers.ListCompanies", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_company_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "name": "Example Consulting", "industry": "konsulent", "website": "https://example.com", "city": "Oslo" } } ] } ``` ### Find a company by name Case-insensitive partial name search. For reliable external-system matching, retain the returned record ID; a name is not unique. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.ListCompanies' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "filters": [ { "field": "data.name", "op": "contains", "value": "Northstar" } ], "sort": { "field": "data.name", "direction": "asc" }, "limit": 50 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.ListCompanies", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "filters": [ { "field": "data.name", "op": "contains", "value": "Northstar" } ], "sort": { "field": "data.name", "direction": "asc" }, "limit": 50 }), }); 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 payload = { "filters": [ { "field": "data.name", "op": "contains", "value": "Northstar" } ], "sort": { "field": "data.name", "direction": "asc" }, "limit": 50 } request = Request( "https://api.brigg.app/v1/operations/customers.ListCompanies", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_company_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "name": "Northstar", "industry": "konsulent", "website": "https://example.com", "city": "Oslo" } } ] } ``` ### Records updated since a checkpoint 6 October 2026 at 00:00 UTC. Use an overlap window and upsert by ID when synchronizing. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.ListCompanies' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.ListCompanies", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 }), }); 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 payload = { "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 } request = Request( "https://api.brigg.app/v1/operations/customers.ListCompanies", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_company_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "name": "Example Consulting", "industry": "konsulent", "website": "https://example.com", "city": "Oslo" } } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "filters": { "type": "array", "items": { "type": "object", "properties": { "field": { "type": "string", "description": "`data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private.", "enum": [ "id", "created_at", "updated_at", "created_by", "private", "data.name", "data.domain", "data.industry", "data.description", "data.owner_ref", "data.website", "data.org_number", "data.registry_country", "data.address", "data.postal_code", "data.city", "data.country", "data.phone", "data.tags", "data.product_lines", "data.profile" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "contains", "starts_with", "gt", "gte", "lt", "lte", "in", "has", "is_empty", "is_not_empty" ], "description": "Comparison operator. Use in with an array, or omit value for is_empty and is_not_empty." }, "value": { "description": "The comparison value; an array for `in`; omitted for is_empty / is_not_empty." } }, "required": [ "field", "op" ], "additionalProperties": false }, "description": "Conditions the row must ALL satisfy." }, "sort": { "type": "object", "properties": { "field": { "type": "string", "description": "`data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private.", "enum": [ "id", "created_at", "updated_at", "created_by", "private", "data.name", "data.domain", "data.industry", "data.description", "data.owner_ref", "data.website", "data.org_number", "data.registry_country", "data.address", "data.postal_code", "data.city", "data.country", "data.phone", "data.tags", "data.product_lines", "data.profile" ] }, "direction": { "type": "string", "enum": [ "asc", "desc" ], "description": "Sort direction: asc for ascending or desc for descending." } }, "required": [ "field" ], "additionalProperties": false, "description": "Sort order for the results. Defaults to updated_at descending, with id as a tie-breaker." }, "limit": { "type": "integer", "minimum": 1, "default": 100, "description": "Maximum number of results to return in this page. Continue with next_cursor when returned." }, "cursor": { "type": "string", "description": "The `next_cursor` of the previous page." } }, "additionalProperties": false, "examples": [ { "filters": [ { "field": "data.industry", "op": "eq", "value": "konsulent" } ], "sort": { "field": "data.name", "direction": "asc" }, "limit": 10 } ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:Company record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "name": { "type": "string", "description": "Company's display name; use org_number and registry_country for its registered identity." }, "domain": { "type": "string", "description": "Website hostname, without a scheme or path." }, "industry": { "type": "string", "enum": [ "bygg", "handel", "konsulent", "it", "helse", "restaurant", "eiendom", "transport", "finans", "utdanning", "industri", "offentlig", "annet" ], "description": "Industry classification. Send the stored enum value; the English label is for display only. Values: `bygg` — Construction; `handel` — Retail and wholesale; `konsulent` — Consulting; `it` — Information technology; `helse` — Healthcare; `restaurant` — Restaurants; `eiendom` — Real estate; `transport` — Transport; `finans` — Finance; `utdanning` — Education; `industri` — Manufacturing; `offentlig` — Public sector; `annet` — Other." }, "description": { "type": "string", "description": "Business description recorded for this company." }, "owner_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "website": { "type": "string", "description": "Company website URL, including https://." }, "org_number": { "type": "string", "description": "Organisation number from the company register, stored as text to preserve leading zeros." }, "registry_country": { "type": "string", "enum": [ "NO", "SE" ], "description": "Country of registration: NO for Norway or SE for Sweden." }, "address": { "type": "string", "description": "Street address, including building or unit when applicable." }, "postal_code": { "type": "string", "description": "Postal code as text, preserving leading zeros." }, "city": { "type": "string", "description": "Postal town or city." }, "country": { "type": "string", "description": "Country associated with the address or record." }, "phone": { "type": "string", "description": "Phone number including its country calling code." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, "product_lines": { "type": "array", "items": { "type": "object", "properties": { "product_ref": { "type": "string", "description": "Product record ID." }, "name": { "type": "string", "description": "Display name." }, "description": { "type": "string", "description": "Descriptive text." }, "quantity": { "type": "number", "minimum": 0, "description": "Number of units. May be fractional when the product allows it." }, "unit": { "type": "string", "description": "Unit used for the quantity, such as hours or items." }, "unit_price_ore": { "type": "integer", "description": "Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only." }, "agreed_at": { "type": "number", "description": "Time the commercial terms were agreed, in Unix milliseconds." }, "agreed_deal_ref": { "type": "string", "description": "Deal record ID." }, "revenue_type": { "type": "string", "enum": [ "one_time", "monthly", "quarterly", "annual" ], "description": "Whether this amount is charged once or repeats monthly, quarterly or annually." }, "start_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" }, "end_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" } }, "required": [ "name" ], "additionalProperties": false }, "description": "Products or services agreed with this company, including quantity, price and billing frequency." }, "profile": { "type": "object", "properties": { "summary": { "type": "string", "description": "Short summary of the source information." }, "highlights": { "type": "array", "items": { "type": "string" }, "description": "Key points extracted from the source information." } }, "additionalProperties": false, "description": "Generated or supplied company profile, with a summary and key facts." } }, "required": [ "name" ], "additionalProperties": false, "description": "The record's fields.", "title": "Company" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "title": "CompanyRecord" }, "description": "Records visible under the credential's grants and the selected data scope, matching the requested filters. Pass next_cursor as cursor to continue when a next cursor is returned." }, "next_cursor": { "type": "string", "description": "Pass this value as cursor to continue with the same filters, sort and credential. Omitted when there are no more results." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "id": "e_company_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "name": "Example Consulting", "industry": "konsulent", "website": "https://example.com", "city": "Oslo" } } ] } ] } ``` --- # Create company Create a company and return the saved record. POST https://api.brigg.app/v1/operations/customers.CreateCompany ## Access & visibility Allow `customers.CreateCompany` on your API key. Resource read permissions: `core:Company`. Resource write permissions: `core:Company`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `data` | [Company](#company-request-data) | Yes | The record's fields. | | `private` | boolean | No | Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance. | ### Company · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Company's display name; use org_number and registry_country for its registered identity. | | `domain` | string | No | Website hostname, without a scheme or path. | | `industry` | string | No | Industry classification. Send the stored enum value; the English label is for display only. Values: `bygg` — Construction; `handel` — Retail and wholesale; `konsulent` — Consulting; `it` — Information technology; `helse` — Healthcare; `restaurant` — Restaurants; `eiendom` — Real estate; `transport` — Transport; `finans` — Finance; `utdanning` — Education; `industri` — Manufacturing; `offentlig` — Public sector; `annet` — Other. | | `description` | string | No | Business description recorded for this company. | | `owner_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `website` | string | No | Company website URL, including https://. | | `org_number` | string | No | Organisation number from the company register, stored as text to preserve leading zeros. | | `registry_country` | string | No | Country of registration: NO for Norway or SE for Sweden. Allowed: `"NO"`, `"SE"`. | | `address` | string | No | Street address, including building or unit when applicable. | | `postal_code` | string | No | Postal code as text, preserving leading zeros. | | `city` | string | No | Postal town or city. | | `country` | string | No | Country associated with the address or record. | | `phone` | string | No | Phone number including its country calling code. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | | `product_lines` | array of [object](#request-data-product-lines) | No | Products or services agreed with this company, including quantity, price and billing frequency. | | `profile` | [object](#request-data-profile) | No | Generated or supplied company profile, with a summary and key facts. | ### request.data.product_lines[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `product_ref` | string | No | Product record ID. | | `name` | string | Yes | Display name. | | `description` | string | No | Descriptive text. | | `quantity` | number | No | Number of units. May be fractional when the product allows it. Minimum: 0. | | `unit` | string | No | Unit used for the quantity, such as hours or items. | | `unit_price_ore` | integer | No | Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only. | | `agreed_at` | number | No | Time the commercial terms were agreed, in Unix milliseconds. | | `agreed_deal_ref` | string | No | Deal record ID. | | `revenue_type` | string | No | Whether this amount is charged once or repeats monthly, quarterly or annually. Allowed: `"one_time"`, `"monthly"`, `"quarterly"`, `"annual"`. | | `start_date` | string | No | ISO date (YYYY-MM-DD) | | `end_date` | string | No | ISO date (YYYY-MM-DD) | ### request.data.profile | Field | Type | Required | Description | | --- | --- | --- | --- | | `summary` | string | No | Short summary of the source information. | | `highlights` | array of string | No | Key points extracted from the source information. | ## Choose ownership deliberately Omitting `private`, or setting it to false, creates a workspace-shared record. Set `private: true` to create a record owned by the approved acting member. Private records require member delegation; a workspace-only credential cannot own a personal record. The credential’s exact resource grants authorize the write; private ownership and project membership remain enforced. A create is a new record, not an upsert. Reuse the same idempotency key only for retries of that logical creation. For recurring synchronization, use the resource’s upsert operation when available: it matches a permanent external reference. Otherwise keep the returned record ID and use the corresponding update operation for subsequent changes. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [CompanyRecord](#companyrecord-response-item) | Yes | The requested record, including its metadata and data fields. | ### CompanyRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Company record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Company](#company-response-item-data) | Yes | The record's fields. | ### Company · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Company's display name; use org_number and registry_country for its registered identity. | | `domain` | string | No | Website hostname, without a scheme or path. | | `industry` | string | No | Industry classification. Send the stored enum value; the English label is for display only. Values: `bygg` — Construction; `handel` — Retail and wholesale; `konsulent` — Consulting; `it` — Information technology; `helse` — Healthcare; `restaurant` — Restaurants; `eiendom` — Real estate; `transport` — Transport; `finans` — Finance; `utdanning` — Education; `industri` — Manufacturing; `offentlig` — Public sector; `annet` — Other. | | `description` | string | No | Business description recorded for this company. | | `owner_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `website` | string | No | Company website URL, including https://. | | `org_number` | string | No | Organisation number from the company register, stored as text to preserve leading zeros. | | `registry_country` | string | No | Country of registration: NO for Norway or SE for Sweden. Allowed: `"NO"`, `"SE"`. | | `address` | string | No | Street address, including building or unit when applicable. | | `postal_code` | string | No | Postal code as text, preserving leading zeros. | | `city` | string | No | Postal town or city. | | `country` | string | No | Country associated with the address or record. | | `phone` | string | No | Phone number including its country calling code. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | | `product_lines` | array of [object](#response-item-data-product-lines) | No | Products or services agreed with this company, including quantity, price and billing frequency. | | `profile` | [object](#response-item-data-profile) | No | Generated or supplied company profile, with a summary and key facts. | ### response.item.data.product_lines[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `product_ref` | string | No | Product record ID. | | `name` | string | Yes | Display name. | | `description` | string | No | Descriptive text. | | `quantity` | number | No | Number of units. May be fractional when the product allows it. Minimum: 0. | | `unit` | string | No | Unit used for the quantity, such as hours or items. | | `unit_price_ore` | integer | No | Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only. | | `agreed_at` | number | No | Time the commercial terms were agreed, in Unix milliseconds. | | `agreed_deal_ref` | string | No | Deal record ID. | | `revenue_type` | string | No | Whether this amount is charged once or repeats monthly, quarterly or annually. Allowed: `"one_time"`, `"monthly"`, `"quarterly"`, `"annual"`. | | `start_date` | string | No | ISO date (YYYY-MM-DD) | | `end_date` | string | No | ISO date (YYYY-MM-DD) | ### response.item.data.profile | Field | Type | Required | Description | | --- | --- | --- | --- | | `summary` | string | No | Short summary of the source information. | | `highlights` | array of string | No | Key points extracted from the source information. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List companies](/developers/reference/customers/ListCompanies) - [Get company](/developers/reference/customers/GetCompany) - [Upsert company](/developers/reference/customers/UpsertCompany) - [Update company](/developers/reference/customers/UpdateCompany) - [Delete company](/developers/reference/customers/DeleteCompany) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.CreateCompany' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "data": { "name": "Example Consulting", "industry": "konsulent", "website": "https://example.com", "city": "Oslo" } }' ``` #### TypeScript ```typescript 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/customers.CreateCompany", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "data": { "name": "Example Consulting", "industry": "konsulent", "website": "https://example.com", "city": "Oslo" } }), }); 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 = { "data": { "name": "Example Consulting", "industry": "konsulent", "website": "https://example.com", "city": "Oslo" } } request = Request( "https://api.brigg.app/v1/operations/customers.CreateCompany", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_company_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "name": "Example Consulting", "industry": "konsulent", "website": "https://example.com", "city": "Oslo" } } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "data": { "type": "object", "properties": { "name": { "type": "string", "description": "Company's display name; use org_number and registry_country for its registered identity." }, "domain": { "type": "string", "description": "Website hostname, without a scheme or path." }, "industry": { "type": "string", "enum": [ "bygg", "handel", "konsulent", "it", "helse", "restaurant", "eiendom", "transport", "finans", "utdanning", "industri", "offentlig", "annet" ], "description": "Industry classification. Send the stored enum value; the English label is for display only. Values: `bygg` — Construction; `handel` — Retail and wholesale; `konsulent` — Consulting; `it` — Information technology; `helse` — Healthcare; `restaurant` — Restaurants; `eiendom` — Real estate; `transport` — Transport; `finans` — Finance; `utdanning` — Education; `industri` — Manufacturing; `offentlig` — Public sector; `annet` — Other." }, "description": { "type": "string", "description": "Business description recorded for this company." }, "owner_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "website": { "type": "string", "description": "Company website URL, including https://." }, "org_number": { "type": "string", "description": "Organisation number from the company register, stored as text to preserve leading zeros." }, "registry_country": { "type": "string", "enum": [ "NO", "SE" ], "description": "Country of registration: NO for Norway or SE for Sweden." }, "address": { "type": "string", "description": "Street address, including building or unit when applicable." }, "postal_code": { "type": "string", "description": "Postal code as text, preserving leading zeros." }, "city": { "type": "string", "description": "Postal town or city." }, "country": { "type": "string", "description": "Country associated with the address or record." }, "phone": { "type": "string", "description": "Phone number including its country calling code." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, "product_lines": { "type": "array", "items": { "type": "object", "properties": { "product_ref": { "type": "string", "description": "Product record ID." }, "name": { "type": "string", "description": "Display name." }, "description": { "type": "string", "description": "Descriptive text." }, "quantity": { "type": "number", "minimum": 0, "description": "Number of units. May be fractional when the product allows it." }, "unit": { "type": "string", "description": "Unit used for the quantity, such as hours or items." }, "unit_price_ore": { "type": "integer", "description": "Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only." }, "agreed_at": { "type": "number", "description": "Time the commercial terms were agreed, in Unix milliseconds." }, "agreed_deal_ref": { "type": "string", "description": "Deal record ID." }, "revenue_type": { "type": "string", "enum": [ "one_time", "monthly", "quarterly", "annual" ], "description": "Whether this amount is charged once or repeats monthly, quarterly or annually." }, "start_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" }, "end_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" } }, "required": [ "name" ], "additionalProperties": false }, "description": "Products or services agreed with this company, including quantity, price and billing frequency." }, "profile": { "type": "object", "properties": { "summary": { "type": "string", "description": "Short summary of the source information." }, "highlights": { "type": "array", "items": { "type": "string" }, "description": "Key points extracted from the source information." } }, "additionalProperties": false, "description": "Generated or supplied company profile, with a summary and key facts." } }, "required": [ "name" ], "additionalProperties": false, "description": "The record's fields.", "title": "Company" }, "private": { "type": "boolean", "description": "Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance." } }, "required": [ "data" ], "additionalProperties": false, "examples": [ { "data": { "name": "Example Consulting", "industry": "konsulent", "website": "https://example.com", "city": "Oslo" } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:Company record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "name": { "type": "string", "description": "Company's display name; use org_number and registry_country for its registered identity." }, "domain": { "type": "string", "description": "Website hostname, without a scheme or path." }, "industry": { "type": "string", "enum": [ "bygg", "handel", "konsulent", "it", "helse", "restaurant", "eiendom", "transport", "finans", "utdanning", "industri", "offentlig", "annet" ], "description": "Industry classification. Send the stored enum value; the English label is for display only. Values: `bygg` — Construction; `handel` — Retail and wholesale; `konsulent` — Consulting; `it` — Information technology; `helse` — Healthcare; `restaurant` — Restaurants; `eiendom` — Real estate; `transport` — Transport; `finans` — Finance; `utdanning` — Education; `industri` — Manufacturing; `offentlig` — Public sector; `annet` — Other." }, "description": { "type": "string", "description": "Business description recorded for this company." }, "owner_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "website": { "type": "string", "description": "Company website URL, including https://." }, "org_number": { "type": "string", "description": "Organisation number from the company register, stored as text to preserve leading zeros." }, "registry_country": { "type": "string", "enum": [ "NO", "SE" ], "description": "Country of registration: NO for Norway or SE for Sweden." }, "address": { "type": "string", "description": "Street address, including building or unit when applicable." }, "postal_code": { "type": "string", "description": "Postal code as text, preserving leading zeros." }, "city": { "type": "string", "description": "Postal town or city." }, "country": { "type": "string", "description": "Country associated with the address or record." }, "phone": { "type": "string", "description": "Phone number including its country calling code." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, "product_lines": { "type": "array", "items": { "type": "object", "properties": { "product_ref": { "type": "string", "description": "Product record ID." }, "name": { "type": "string", "description": "Display name." }, "description": { "type": "string", "description": "Descriptive text." }, "quantity": { "type": "number", "minimum": 0, "description": "Number of units. May be fractional when the product allows it." }, "unit": { "type": "string", "description": "Unit used for the quantity, such as hours or items." }, "unit_price_ore": { "type": "integer", "description": "Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only." }, "agreed_at": { "type": "number", "description": "Time the commercial terms were agreed, in Unix milliseconds." }, "agreed_deal_ref": { "type": "string", "description": "Deal record ID." }, "revenue_type": { "type": "string", "enum": [ "one_time", "monthly", "quarterly", "annual" ], "description": "Whether this amount is charged once or repeats monthly, quarterly or annually." }, "start_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" }, "end_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" } }, "required": [ "name" ], "additionalProperties": false }, "description": "Products or services agreed with this company, including quantity, price and billing frequency." }, "profile": { "type": "object", "properties": { "summary": { "type": "string", "description": "Short summary of the source information." }, "highlights": { "type": "array", "items": { "type": "string" }, "description": "Key points extracted from the source information." } }, "additionalProperties": false, "description": "Generated or supplied company profile, with a summary and key facts." } }, "required": [ "name" ], "additionalProperties": false, "description": "The record's fields.", "title": "Company" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "CompanyRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_company_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "name": "Example Consulting", "industry": "konsulent", "website": "https://example.com", "city": "Oslo" } } } ] } ``` --- # Delete company Delete a company by ID. Repeating a deletion returns already_deleted. POST https://api.brigg.app/v1/operations/customers.DeleteCompany ## Access & visibility Allow `customers.DeleteCompany` on your API key. Resource read permissions: `core:Company`. Resource write permissions: `core:Company`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies). Use the record's top-level `id`, not a business field or account ID. | | `expected` | [object](#request-expected) | No | Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {"$absent":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource. | ### request.expected | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string or [object](#request-expected-name) | No | Commit only if the previous name value matches; use $absent to require that this field is missing. | | `domain` | string or [object](#request-expected-domain) | No | Commit only if the previous domain value matches; use $absent to require that this field is missing. | | `industry` | string or [object](#request-expected-industry) | No | Commit only if the previous industry value matches; use $absent to require that this field is missing. | | `description` | string or [object](#request-expected-description) | No | Commit only if the previous description value matches; use $absent to require that this field is missing. | | `owner_ref` | string or [object](#request-expected-owner-ref) | No | Commit only if the previous owner_ref value matches; use $absent to require that this field is missing. | | `website` | string or [object](#request-expected-website) | No | Commit only if the previous website value matches; use $absent to require that this field is missing. | | `org_number` | string or [object](#request-expected-org-number) | No | Commit only if the previous org_number value matches; use $absent to require that this field is missing. | | `registry_country` | string or [object](#request-expected-registry-country) | No | Commit only if the previous registry_country value matches; use $absent to require that this field is missing. | | `address` | string or [object](#request-expected-address) | No | Commit only if the previous address value matches; use $absent to require that this field is missing. | | `postal_code` | string or [object](#request-expected-postal-code) | No | Commit only if the previous postal_code value matches; use $absent to require that this field is missing. | | `city` | string or [object](#request-expected-city) | No | Commit only if the previous city value matches; use $absent to require that this field is missing. | | `country` | string or [object](#request-expected-country) | No | Commit only if the previous country value matches; use $absent to require that this field is missing. | | `phone` | string or [object](#request-expected-phone) | No | Commit only if the previous phone value matches; use $absent to require that this field is missing. | | `tags` | array of string or [object](#request-expected-tags) | No | Commit only if the previous tags value matches; use $absent to require that this field is missing. | | `product_lines` | array of [object](#request-expected-product-lines) or [object](#request-expected-product-lines) | No | Commit only if the previous product_lines value matches; use $absent to require that this field is missing. | | `profile` | [object (2 variants)](#request-expected-profile) | No | Commit only if the previous profile value matches; use $absent to require that this field is missing. | ### request.expected.name | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.domain | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.industry | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.description | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.owner_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.website | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.org_number | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.registry_country | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.address | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.postal_code | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.city | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.country | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.phone | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.tags | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.product_lines | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.product_lines[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `product_ref` | string | No | Product record ID. | | `name` | string | Yes | Display name. | | `description` | string | No | Descriptive text. | | `quantity` | number | No | Number of units. May be fractional when the product allows it. Minimum: 0. | | `unit` | string | No | Unit used for the quantity, such as hours or items. | | `unit_price_ore` | integer | No | Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only. | | `agreed_at` | number | No | Time the commercial terms were agreed, in Unix milliseconds. | | `agreed_deal_ref` | string | No | Deal record ID. | | `revenue_type` | string | No | Whether this amount is charged once or repeats monthly, quarterly or annually. Allowed: `"one_time"`, `"monthly"`, `"quarterly"`, `"annual"`. | | `start_date` | string | No | ISO date (YYYY-MM-DD) | | `end_date` | string | No | ISO date (YYYY-MM-DD) | ### request.expected.profile #### Variant 1 | Field | Type | Required | Description | | --- | --- | --- | --- | | `summary` | string | No | Short summary of the source information. | | `highlights` | array of string | No | Key points extracted from the source information. | #### $absent = true | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ## Deletion and retries A successful response reports whether this call removed the record or it was already absent. Check `cascaded` for dependent record IDs returned by the operation. Retrying the same action uses the original idempotency key. A successful deletion is not an archive you can restore through this operation. To avoid deleting a record someone has changed, read it first and put the relevant prior business values in `expected`. Keys are relative to `data`, not prefixed with `data.`. Use {"$absent": true} to require a missing field. A mismatch returns 409 conflict; read again and decide whether deletion is still appropriate. A revised action needs a new idempotency key. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `deleted` | string | Yes | deleted when this request removed the record; already_deleted when it was already absent. Allowed: `"deleted"`, `"already_deleted"`. | | `cascaded` | array of string | No | IDs of dependent records deleted with this 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `conflict` | A supplied expected value no longer matches. Read the record again before deciding whether to retry. | ## Next steps - [List companies](/developers/reference/customers/ListCompanies) - [Get company](/developers/reference/customers/GetCompany) - [Create company](/developers/reference/customers/CreateCompany) - [Upsert company](/developers/reference/customers/UpsertCompany) - [Update company](/developers/reference/customers/UpdateCompany) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.DeleteCompany' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_company_example" }' ``` #### TypeScript ```typescript 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/customers.DeleteCompany", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_company_example" }), }); 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_company_example" } request = Request( "https://api.brigg.app/v1/operations/customers.DeleteCompany", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "deleted": "deleted" } ``` ### Delete only if unchanged Use a value you actually read. A concurrent change refuses the write with 409 conflict. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.DeleteCompany' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_company_example", "expected": { "name": "Example Consulting" } }' ``` #### TypeScript ```typescript 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/customers.DeleteCompany", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_company_example", "expected": { "name": "Example Consulting" } }), }); 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_company_example", "expected": { "name": "Example Consulting" } } request = Request( "https://api.brigg.app/v1/operations/customers.DeleteCompany", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "deleted": "deleted" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies). Use the record's top-level `id`, not a business field or account ID." }, "expected": { "type": "object", "description": "Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {\"$absent\":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource.", "additionalProperties": false, "properties": { "name": { "description": "Commit only if the previous name value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Company's display name; use org_number and registry_country for its registered identity." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "domain": { "description": "Commit only if the previous domain value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Website hostname, without a scheme or path." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "industry": { "description": "Commit only if the previous industry value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "enum": [ "bygg", "handel", "konsulent", "it", "helse", "restaurant", "eiendom", "transport", "finans", "utdanning", "industri", "offentlig", "annet" ], "description": "Industry classification. Send the stored enum value; the English label is for display only. Values: `bygg` — Construction; `handel` — Retail and wholesale; `konsulent` — Consulting; `it` — Information technology; `helse` — Healthcare; `restaurant` — Restaurants; `eiendom` — Real estate; `transport` — Transport; `finans` — Finance; `utdanning` — Education; `industri` — Manufacturing; `offentlig` — Public sector; `annet` — Other." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "description": { "description": "Commit only if the previous description value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Business description recorded for this company." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "owner_ref": { "description": "Commit only if the previous owner_ref value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "website": { "description": "Commit only if the previous website value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Company website URL, including https://." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "org_number": { "description": "Commit only if the previous org_number value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Organisation number from the company register, stored as text to preserve leading zeros." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "registry_country": { "description": "Commit only if the previous registry_country value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "enum": [ "NO", "SE" ], "description": "Country of registration: NO for Norway or SE for Sweden." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "address": { "description": "Commit only if the previous address value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Street address, including building or unit when applicable." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "postal_code": { "description": "Commit only if the previous postal_code value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Postal code as text, preserving leading zeros." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "city": { "description": "Commit only if the previous city value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Postal town or city." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "country": { "description": "Commit only if the previous country value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Country associated with the address or record." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "phone": { "description": "Commit only if the previous phone value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Phone number including its country calling code." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "tags": { "description": "Commit only if the previous tags value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "product_lines": { "description": "Commit only if the previous product_lines value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "type": "object", "properties": { "product_ref": { "type": "string", "description": "Product record ID." }, "name": { "type": "string", "description": "Display name." }, "description": { "type": "string", "description": "Descriptive text." }, "quantity": { "type": "number", "minimum": 0, "description": "Number of units. May be fractional when the product allows it." }, "unit": { "type": "string", "description": "Unit used for the quantity, such as hours or items." }, "unit_price_ore": { "type": "integer", "description": "Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only." }, "agreed_at": { "type": "number", "description": "Time the commercial terms were agreed, in Unix milliseconds." }, "agreed_deal_ref": { "type": "string", "description": "Deal record ID." }, "revenue_type": { "type": "string", "enum": [ "one_time", "monthly", "quarterly", "annual" ], "description": "Whether this amount is charged once or repeats monthly, quarterly or annually." }, "start_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" }, "end_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" } }, "required": [ "name" ], "additionalProperties": false }, "description": "Products or services agreed with this company, including quantity, price and billing frequency." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "profile": { "description": "Commit only if the previous profile value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "object", "properties": { "summary": { "type": "string", "description": "Short summary of the source information." }, "highlights": { "type": "array", "items": { "type": "string" }, "description": "Key points extracted from the source information." } }, "additionalProperties": false, "description": "Generated or supplied company profile, with a summary and key facts." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] } } } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_company_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "deleted": { "type": "string", "enum": [ "deleted", "already_deleted" ], "description": "deleted when this request removed the record; already_deleted when it was already absent." }, "cascaded": { "type": "array", "items": { "type": "string" }, "description": "IDs of dependent records deleted with this record." } }, "required": [ "deleted" ], "additionalProperties": false, "examples": [ { "deleted": "deleted" } ] } ``` --- # Update company Update a company by ID. Omitted fields stay unchanged; use unset to remove fields and expected to prevent overwriting a concurrent change. POST https://api.brigg.app/v1/operations/customers.UpdateCompany ## Access & visibility Allow `customers.UpdateCompany` on your API key. Resource read permissions: `core:Company`. Resource write permissions: `core:Company`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies). Use the record's top-level `id`, not a business field or account ID. | | `data` | [Company](#company-request-data) | No | The fields to set. | | `unset` | array of string | No | Keys of `data` to remove. Each item: `"name"`, `"domain"`, `"industry"`, `"description"`, `"owner_ref"`, `"website"`, `"org_number"`, `"registry_country"`, `"address"`, `"postal_code"`, `"city"`, `"country"`, `"phone"`, `"tags"`, `"product_lines"`, `"profile"`. | | `expected` | [object](#request-expected) | No | Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {"$absent":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource. | ### Company · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | No | Company's display name; use org_number and registry_country for its registered identity. | | `domain` | string | No | Website hostname, without a scheme or path. | | `industry` | string | No | Industry classification. Send the stored enum value; the English label is for display only. Values: `bygg` — Construction; `handel` — Retail and wholesale; `konsulent` — Consulting; `it` — Information technology; `helse` — Healthcare; `restaurant` — Restaurants; `eiendom` — Real estate; `transport` — Transport; `finans` — Finance; `utdanning` — Education; `industri` — Manufacturing; `offentlig` — Public sector; `annet` — Other. | | `description` | string | No | Business description recorded for this company. | | `owner_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `website` | string | No | Company website URL, including https://. | | `org_number` | string | No | Organisation number from the company register, stored as text to preserve leading zeros. | | `registry_country` | string | No | Country of registration: NO for Norway or SE for Sweden. Allowed: `"NO"`, `"SE"`. | | `address` | string | No | Street address, including building or unit when applicable. | | `postal_code` | string | No | Postal code as text, preserving leading zeros. | | `city` | string | No | Postal town or city. | | `country` | string | No | Country associated with the address or record. | | `phone` | string | No | Phone number including its country calling code. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | | `product_lines` | array of [object](#request-data-product-lines) | No | Products or services agreed with this company, including quantity, price and billing frequency. | | `profile` | [object](#request-data-profile) | No | Generated or supplied company profile, with a summary and key facts. | ### request.data.product_lines[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `product_ref` | string | No | Product record ID. | | `name` | string | Yes | Display name. | | `description` | string | No | Descriptive text. | | `quantity` | number | No | Number of units. May be fractional when the product allows it. Minimum: 0. | | `unit` | string | No | Unit used for the quantity, such as hours or items. | | `unit_price_ore` | integer | No | Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only. | | `agreed_at` | number | No | Time the commercial terms were agreed, in Unix milliseconds. | | `agreed_deal_ref` | string | No | Deal record ID. | | `revenue_type` | string | No | Whether this amount is charged once or repeats monthly, quarterly or annually. Allowed: `"one_time"`, `"monthly"`, `"quarterly"`, `"annual"`. | | `start_date` | string | No | ISO date (YYYY-MM-DD) | | `end_date` | string | No | ISO date (YYYY-MM-DD) | ### request.data.profile | Field | Type | Required | Description | | --- | --- | --- | --- | | `summary` | string | No | Short summary of the source information. | | `highlights` | array of string | No | Key points extracted from the source information. | ### request.expected | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string or [object](#request-expected-name) | No | Commit only if the previous name value matches; use $absent to require that this field is missing. | | `domain` | string or [object](#request-expected-domain) | No | Commit only if the previous domain value matches; use $absent to require that this field is missing. | | `industry` | string or [object](#request-expected-industry) | No | Commit only if the previous industry value matches; use $absent to require that this field is missing. | | `description` | string or [object](#request-expected-description) | No | Commit only if the previous description value matches; use $absent to require that this field is missing. | | `owner_ref` | string or [object](#request-expected-owner-ref) | No | Commit only if the previous owner_ref value matches; use $absent to require that this field is missing. | | `website` | string or [object](#request-expected-website) | No | Commit only if the previous website value matches; use $absent to require that this field is missing. | | `org_number` | string or [object](#request-expected-org-number) | No | Commit only if the previous org_number value matches; use $absent to require that this field is missing. | | `registry_country` | string or [object](#request-expected-registry-country) | No | Commit only if the previous registry_country value matches; use $absent to require that this field is missing. | | `address` | string or [object](#request-expected-address) | No | Commit only if the previous address value matches; use $absent to require that this field is missing. | | `postal_code` | string or [object](#request-expected-postal-code) | No | Commit only if the previous postal_code value matches; use $absent to require that this field is missing. | | `city` | string or [object](#request-expected-city) | No | Commit only if the previous city value matches; use $absent to require that this field is missing. | | `country` | string or [object](#request-expected-country) | No | Commit only if the previous country value matches; use $absent to require that this field is missing. | | `phone` | string or [object](#request-expected-phone) | No | Commit only if the previous phone value matches; use $absent to require that this field is missing. | | `tags` | array of string or [object](#request-expected-tags) | No | Commit only if the previous tags value matches; use $absent to require that this field is missing. | | `product_lines` | array of [object](#request-expected-product-lines) or [object](#request-expected-product-lines) | No | Commit only if the previous product_lines value matches; use $absent to require that this field is missing. | | `profile` | [object (2 variants)](#request-expected-profile) | No | Commit only if the previous profile value matches; use $absent to require that this field is missing. | ### request.expected.name | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.domain | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.industry | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.description | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.owner_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.website | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.org_number | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.registry_country | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.address | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.postal_code | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.city | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.country | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.phone | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.tags | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.product_lines | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.product_lines[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `product_ref` | string | No | Product record ID. | | `name` | string | Yes | Display name. | | `description` | string | No | Descriptive text. | | `quantity` | number | No | Number of units. May be fractional when the product allows it. Minimum: 0. | | `unit` | string | No | Unit used for the quantity, such as hours or items. | | `unit_price_ore` | integer | No | Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only. | | `agreed_at` | number | No | Time the commercial terms were agreed, in Unix milliseconds. | | `agreed_deal_ref` | string | No | Deal record ID. | | `revenue_type` | string | No | Whether this amount is charged once or repeats monthly, quarterly or annually. Allowed: `"one_time"`, `"monthly"`, `"quarterly"`, `"annual"`. | | `start_date` | string | No | ISO date (YYYY-MM-DD) | | `end_date` | string | No | ISO date (YYYY-MM-DD) | ### request.expected.profile #### Variant 1 | Field | Type | Required | Description | | --- | --- | --- | --- | | `summary` | string | No | Short summary of the source information. | | `highlights` | array of string | No | Key points extracted from the source information. | #### $absent = true | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ## Update without losing changes Send only the business fields you want to change in `data`; omitted fields stay unchanged. Use `unset` to remove an optional field. Setting a field to null is a different action and is allowed only when its schema permits null. Use `expected` for a conditional update: supply the values you last read for the fields whose concurrent changes would matter. `{"$absent": true}` expects a missing field. A conflict means you must read the record again and decide how to reconcile the change. Keep the same idempotency key when retrying the original action; use a new key for a revised action. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [CompanyRecord](#companyrecord-response-item) | Yes | The requested record, including its metadata and data fields. | ### CompanyRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Company record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Company](#company-response-item-data) | Yes | The record's fields. | ### Company · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Company's display name; use org_number and registry_country for its registered identity. | | `domain` | string | No | Website hostname, without a scheme or path. | | `industry` | string | No | Industry classification. Send the stored enum value; the English label is for display only. Values: `bygg` — Construction; `handel` — Retail and wholesale; `konsulent` — Consulting; `it` — Information technology; `helse` — Healthcare; `restaurant` — Restaurants; `eiendom` — Real estate; `transport` — Transport; `finans` — Finance; `utdanning` — Education; `industri` — Manufacturing; `offentlig` — Public sector; `annet` — Other. | | `description` | string | No | Business description recorded for this company. | | `owner_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `website` | string | No | Company website URL, including https://. | | `org_number` | string | No | Organisation number from the company register, stored as text to preserve leading zeros. | | `registry_country` | string | No | Country of registration: NO for Norway or SE for Sweden. Allowed: `"NO"`, `"SE"`. | | `address` | string | No | Street address, including building or unit when applicable. | | `postal_code` | string | No | Postal code as text, preserving leading zeros. | | `city` | string | No | Postal town or city. | | `country` | string | No | Country associated with the address or record. | | `phone` | string | No | Phone number including its country calling code. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | | `product_lines` | array of [object](#response-item-data-product-lines) | No | Products or services agreed with this company, including quantity, price and billing frequency. | | `profile` | [object](#response-item-data-profile) | No | Generated or supplied company profile, with a summary and key facts. | ### response.item.data.product_lines[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `product_ref` | string | No | Product record ID. | | `name` | string | Yes | Display name. | | `description` | string | No | Descriptive text. | | `quantity` | number | No | Number of units. May be fractional when the product allows it. Minimum: 0. | | `unit` | string | No | Unit used for the quantity, such as hours or items. | | `unit_price_ore` | integer | No | Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only. | | `agreed_at` | number | No | Time the commercial terms were agreed, in Unix milliseconds. | | `agreed_deal_ref` | string | No | Deal record ID. | | `revenue_type` | string | No | Whether this amount is charged once or repeats monthly, quarterly or annually. Allowed: `"one_time"`, `"monthly"`, `"quarterly"`, `"annual"`. | | `start_date` | string | No | ISO date (YYYY-MM-DD) | | `end_date` | string | No | ISO date (YYYY-MM-DD) | ### response.item.data.profile | Field | Type | Required | Description | | --- | --- | --- | --- | | `summary` | string | No | Short summary of the source information. | | `highlights` | array of string | No | Key points extracted from the source information. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `conflict` | A supplied expected value no longer matches. Read the record again before deciding whether to retry. | ## Next steps - [List companies](/developers/reference/customers/ListCompanies) - [Get company](/developers/reference/customers/GetCompany) - [Create company](/developers/reference/customers/CreateCompany) - [Upsert company](/developers/reference/customers/UpsertCompany) - [Delete company](/developers/reference/customers/DeleteCompany) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.UpdateCompany' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_company_example", "data": { "city": "Bergen" }, "expected": { "city": "Oslo" } }' ``` #### TypeScript ```typescript 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/customers.UpdateCompany", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_company_example", "data": { "city": "Bergen" }, "expected": { "city": "Oslo" } }), }); 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_company_example", "data": { "city": "Bergen" }, "expected": { "city": "Oslo" } } request = Request( "https://api.brigg.app/v1/operations/customers.UpdateCompany", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_company_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "name": "Example Consulting", "industry": "konsulent", "website": "https://example.com", "city": "Bergen" } } } ``` ### Update only if unchanged Use a value you actually read. A concurrent change refuses the write with 409 conflict. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.UpdateCompany' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_company_example", "data": { "city": "Bergen" }, "expected": { "name": "Example Consulting" } }' ``` #### TypeScript ```typescript 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/customers.UpdateCompany", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_company_example", "data": { "city": "Bergen" }, "expected": { "name": "Example Consulting" } }), }); 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_company_example", "data": { "city": "Bergen" }, "expected": { "name": "Example Consulting" } } request = Request( "https://api.brigg.app/v1/operations/customers.UpdateCompany", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_company_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "name": "Example Consulting", "industry": "konsulent", "website": "https://example.com", "city": "Bergen" } } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies). Use the record's top-level `id`, not a business field or account ID." }, "data": { "type": "object", "properties": { "name": { "type": "string", "description": "Company's display name; use org_number and registry_country for its registered identity." }, "domain": { "type": "string", "description": "Website hostname, without a scheme or path." }, "industry": { "type": "string", "enum": [ "bygg", "handel", "konsulent", "it", "helse", "restaurant", "eiendom", "transport", "finans", "utdanning", "industri", "offentlig", "annet" ], "description": "Industry classification. Send the stored enum value; the English label is for display only. Values: `bygg` — Construction; `handel` — Retail and wholesale; `konsulent` — Consulting; `it` — Information technology; `helse` — Healthcare; `restaurant` — Restaurants; `eiendom` — Real estate; `transport` — Transport; `finans` — Finance; `utdanning` — Education; `industri` — Manufacturing; `offentlig` — Public sector; `annet` — Other." }, "description": { "type": "string", "description": "Business description recorded for this company." }, "owner_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "website": { "type": "string", "description": "Company website URL, including https://." }, "org_number": { "type": "string", "description": "Organisation number from the company register, stored as text to preserve leading zeros." }, "registry_country": { "type": "string", "enum": [ "NO", "SE" ], "description": "Country of registration: NO for Norway or SE for Sweden." }, "address": { "type": "string", "description": "Street address, including building or unit when applicable." }, "postal_code": { "type": "string", "description": "Postal code as text, preserving leading zeros." }, "city": { "type": "string", "description": "Postal town or city." }, "country": { "type": "string", "description": "Country associated with the address or record." }, "phone": { "type": "string", "description": "Phone number including its country calling code." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, "product_lines": { "type": "array", "items": { "type": "object", "properties": { "product_ref": { "type": "string", "description": "Product record ID." }, "name": { "type": "string", "description": "Display name." }, "description": { "type": "string", "description": "Descriptive text." }, "quantity": { "type": "number", "minimum": 0, "description": "Number of units. May be fractional when the product allows it." }, "unit": { "type": "string", "description": "Unit used for the quantity, such as hours or items." }, "unit_price_ore": { "type": "integer", "description": "Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only." }, "agreed_at": { "type": "number", "description": "Time the commercial terms were agreed, in Unix milliseconds." }, "agreed_deal_ref": { "type": "string", "description": "Deal record ID." }, "revenue_type": { "type": "string", "enum": [ "one_time", "monthly", "quarterly", "annual" ], "description": "Whether this amount is charged once or repeats monthly, quarterly or annually." }, "start_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" }, "end_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" } }, "required": [ "name" ], "additionalProperties": false }, "description": "Products or services agreed with this company, including quantity, price and billing frequency." }, "profile": { "type": "object", "properties": { "summary": { "type": "string", "description": "Short summary of the source information." }, "highlights": { "type": "array", "items": { "type": "string" }, "description": "Key points extracted from the source information." } }, "additionalProperties": false, "description": "Generated or supplied company profile, with a summary and key facts." } }, "required": [], "additionalProperties": false, "description": "The fields to set.", "title": "Company" }, "unset": { "type": "array", "items": { "type": "string", "enum": [ "name", "domain", "industry", "description", "owner_ref", "website", "org_number", "registry_country", "address", "postal_code", "city", "country", "phone", "tags", "product_lines", "profile" ] }, "description": "Keys of `data` to remove." }, "expected": { "type": "object", "description": "Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {\"$absent\":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource.", "additionalProperties": false, "properties": { "name": { "description": "Commit only if the previous name value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Company's display name; use org_number and registry_country for its registered identity." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "domain": { "description": "Commit only if the previous domain value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Website hostname, without a scheme or path." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "industry": { "description": "Commit only if the previous industry value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "enum": [ "bygg", "handel", "konsulent", "it", "helse", "restaurant", "eiendom", "transport", "finans", "utdanning", "industri", "offentlig", "annet" ], "description": "Industry classification. Send the stored enum value; the English label is for display only. Values: `bygg` — Construction; `handel` — Retail and wholesale; `konsulent` — Consulting; `it` — Information technology; `helse` — Healthcare; `restaurant` — Restaurants; `eiendom` — Real estate; `transport` — Transport; `finans` — Finance; `utdanning` — Education; `industri` — Manufacturing; `offentlig` — Public sector; `annet` — Other." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "description": { "description": "Commit only if the previous description value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Business description recorded for this company." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "owner_ref": { "description": "Commit only if the previous owner_ref value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "website": { "description": "Commit only if the previous website value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Company website URL, including https://." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "org_number": { "description": "Commit only if the previous org_number value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Organisation number from the company register, stored as text to preserve leading zeros." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "registry_country": { "description": "Commit only if the previous registry_country value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "enum": [ "NO", "SE" ], "description": "Country of registration: NO for Norway or SE for Sweden." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "address": { "description": "Commit only if the previous address value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Street address, including building or unit when applicable." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "postal_code": { "description": "Commit only if the previous postal_code value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Postal code as text, preserving leading zeros." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "city": { "description": "Commit only if the previous city value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Postal town or city." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "country": { "description": "Commit only if the previous country value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Country associated with the address or record." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "phone": { "description": "Commit only if the previous phone value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Phone number including its country calling code." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "tags": { "description": "Commit only if the previous tags value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "product_lines": { "description": "Commit only if the previous product_lines value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "type": "object", "properties": { "product_ref": { "type": "string", "description": "Product record ID." }, "name": { "type": "string", "description": "Display name." }, "description": { "type": "string", "description": "Descriptive text." }, "quantity": { "type": "number", "minimum": 0, "description": "Number of units. May be fractional when the product allows it." }, "unit": { "type": "string", "description": "Unit used for the quantity, such as hours or items." }, "unit_price_ore": { "type": "integer", "description": "Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only." }, "agreed_at": { "type": "number", "description": "Time the commercial terms were agreed, in Unix milliseconds." }, "agreed_deal_ref": { "type": "string", "description": "Deal record ID." }, "revenue_type": { "type": "string", "enum": [ "one_time", "monthly", "quarterly", "annual" ], "description": "Whether this amount is charged once or repeats monthly, quarterly or annually." }, "start_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" }, "end_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" } }, "required": [ "name" ], "additionalProperties": false }, "description": "Products or services agreed with this company, including quantity, price and billing frequency." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "profile": { "description": "Commit only if the previous profile value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "object", "properties": { "summary": { "type": "string", "description": "Short summary of the source information." }, "highlights": { "type": "array", "items": { "type": "string" }, "description": "Key points extracted from the source information." } }, "additionalProperties": false, "description": "Generated or supplied company profile, with a summary and key facts." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] } } } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_company_example", "data": { "city": "Bergen" }, "expected": { "city": "Oslo" } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:Company record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "name": { "type": "string", "description": "Company's display name; use org_number and registry_country for its registered identity." }, "domain": { "type": "string", "description": "Website hostname, without a scheme or path." }, "industry": { "type": "string", "enum": [ "bygg", "handel", "konsulent", "it", "helse", "restaurant", "eiendom", "transport", "finans", "utdanning", "industri", "offentlig", "annet" ], "description": "Industry classification. Send the stored enum value; the English label is for display only. Values: `bygg` — Construction; `handel` — Retail and wholesale; `konsulent` — Consulting; `it` — Information technology; `helse` — Healthcare; `restaurant` — Restaurants; `eiendom` — Real estate; `transport` — Transport; `finans` — Finance; `utdanning` — Education; `industri` — Manufacturing; `offentlig` — Public sector; `annet` — Other." }, "description": { "type": "string", "description": "Business description recorded for this company." }, "owner_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "website": { "type": "string", "description": "Company website URL, including https://." }, "org_number": { "type": "string", "description": "Organisation number from the company register, stored as text to preserve leading zeros." }, "registry_country": { "type": "string", "enum": [ "NO", "SE" ], "description": "Country of registration: NO for Norway or SE for Sweden." }, "address": { "type": "string", "description": "Street address, including building or unit when applicable." }, "postal_code": { "type": "string", "description": "Postal code as text, preserving leading zeros." }, "city": { "type": "string", "description": "Postal town or city." }, "country": { "type": "string", "description": "Country associated with the address or record." }, "phone": { "type": "string", "description": "Phone number including its country calling code." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, "product_lines": { "type": "array", "items": { "type": "object", "properties": { "product_ref": { "type": "string", "description": "Product record ID." }, "name": { "type": "string", "description": "Display name." }, "description": { "type": "string", "description": "Descriptive text." }, "quantity": { "type": "number", "minimum": 0, "description": "Number of units. May be fractional when the product allows it." }, "unit": { "type": "string", "description": "Unit used for the quantity, such as hours or items." }, "unit_price_ore": { "type": "integer", "description": "Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only." }, "agreed_at": { "type": "number", "description": "Time the commercial terms were agreed, in Unix milliseconds." }, "agreed_deal_ref": { "type": "string", "description": "Deal record ID." }, "revenue_type": { "type": "string", "enum": [ "one_time", "monthly", "quarterly", "annual" ], "description": "Whether this amount is charged once or repeats monthly, quarterly or annually." }, "start_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" }, "end_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" } }, "required": [ "name" ], "additionalProperties": false }, "description": "Products or services agreed with this company, including quantity, price and billing frequency." }, "profile": { "type": "object", "properties": { "summary": { "type": "string", "description": "Short summary of the source information." }, "highlights": { "type": "array", "items": { "type": "string" }, "description": "Key points extracted from the source information." } }, "additionalProperties": false, "description": "Generated or supplied company profile, with a summary and key facts." } }, "required": [ "name" ], "additionalProperties": false, "description": "The record's fields.", "title": "Company" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "CompanyRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_company_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "name": "Example Consulting", "industry": "konsulent", "website": "https://example.com", "city": "Bergen" } } } ] } ``` --- # Upsert company Create or update a company by a permanent external reference. Matching is exact within the workspace, resource type and ownership scope. Supplied fields replace their values; omitted fields stay unchanged. Deleted records are not recreated. POST https://api.brigg.app/v1/operations/customers.UpsertCompany ## Access & visibility Allow `customers.UpsertCompany` on your API key. Resource read permissions: `core:Company`. Resource write permissions: `core:Company`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `data` | [Company](#company-request-data) | Yes | The record's fields. | | `private` | boolean | No | Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance. | | `external_ref` | [object](#request-external-ref) | Yes | Permanent, case-sensitive source identity within this workspace, resource type and private/workspace scope. It is independent of API key rotation and retry receipt expiry. | ### Company · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Company's display name; use org_number and registry_country for its registered identity. | | `domain` | string | No | Website hostname, without a scheme or path. | | `industry` | string | No | Industry classification. Send the stored enum value; the English label is for display only. Values: `bygg` — Construction; `handel` — Retail and wholesale; `konsulent` — Consulting; `it` — Information technology; `helse` — Healthcare; `restaurant` — Restaurants; `eiendom` — Real estate; `transport` — Transport; `finans` — Finance; `utdanning` — Education; `industri` — Manufacturing; `offentlig` — Public sector; `annet` — Other. | | `description` | string | No | Business description recorded for this company. | | `owner_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `website` | string | No | Company website URL, including https://. | | `org_number` | string | No | Organisation number from the company register, stored as text to preserve leading zeros. | | `registry_country` | string | No | Country of registration: NO for Norway or SE for Sweden. Allowed: `"NO"`, `"SE"`. | | `address` | string | No | Street address, including building or unit when applicable. | | `postal_code` | string | No | Postal code as text, preserving leading zeros. | | `city` | string | No | Postal town or city. | | `country` | string | No | Country associated with the address or record. | | `phone` | string | No | Phone number including its country calling code. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | | `product_lines` | array of [object](#request-data-product-lines) | No | Products or services agreed with this company, including quantity, price and billing frequency. | | `profile` | [object](#request-data-profile) | No | Generated or supplied company profile, with a summary and key facts. | ### request.data.product_lines[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `product_ref` | string | No | Product record ID. | | `name` | string | Yes | Display name. | | `description` | string | No | Descriptive text. | | `quantity` | number | No | Number of units. May be fractional when the product allows it. Minimum: 0. | | `unit` | string | No | Unit used for the quantity, such as hours or items. | | `unit_price_ore` | integer | No | Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only. | | `agreed_at` | number | No | Time the commercial terms were agreed, in Unix milliseconds. | | `agreed_deal_ref` | string | No | Deal record ID. | | `revenue_type` | string | No | Whether this amount is charged once or repeats monthly, quarterly or annually. Allowed: `"one_time"`, `"monthly"`, `"quarterly"`, `"annual"`. | | `start_date` | string | No | ISO date (YYYY-MM-DD) | | `end_date` | string | No | ISO date (YYYY-MM-DD) | ### request.data.profile | Field | Type | Required | Description | | --- | --- | --- | --- | | `summary` | string | No | Short summary of the source information. | | `highlights` | array of string | No | Key points extracted from the source information. | ### request.external_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `namespace` | string | Yes | A stable name for the source system, such as crm-production. At least 1 character. | | `id` | string | Yes | The record ID in that source system. At least 1 character. | ## Sync with a permanent external reference Choose a stable `external_ref.namespace` for your source system and put its record ID in `external_ref.id`. Matching is case-sensitive and scoped to this workspace, resource type and private/workspace ownership. The reference survives API key replacement and the 30-day retry receipt window. It does not match records by email or name. Send the required create fields each time. A missing reference creates a record; an existing reference updates only supplied fields and preserves everything else. `created` tells you which happened. Use the same idempotency key when retrying a lost response and a new key for a later source change. Concurrent calls cannot create duplicate records. A deleted or inaccessible match is refused; the operation does not restore it or make a replacement. Use the returned `item.id` with the regular update operation when you need `unset` or a conditional `expected` edit. Changing `private` chooses a different ownership scope; it does not transfer an existing record. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [CompanyRecord](#companyrecord-response-item) | Yes | The requested record, including its metadata and data fields. | | `created` | boolean | Yes | True when this external reference created a record; false when it matched an existing record. | ### CompanyRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Company record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Company](#company-response-item-data) | Yes | The record's fields. | ### Company · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Company's display name; use org_number and registry_country for its registered identity. | | `domain` | string | No | Website hostname, without a scheme or path. | | `industry` | string | No | Industry classification. Send the stored enum value; the English label is for display only. Values: `bygg` — Construction; `handel` — Retail and wholesale; `konsulent` — Consulting; `it` — Information technology; `helse` — Healthcare; `restaurant` — Restaurants; `eiendom` — Real estate; `transport` — Transport; `finans` — Finance; `utdanning` — Education; `industri` — Manufacturing; `offentlig` — Public sector; `annet` — Other. | | `description` | string | No | Business description recorded for this company. | | `owner_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `website` | string | No | Company website URL, including https://. | | `org_number` | string | No | Organisation number from the company register, stored as text to preserve leading zeros. | | `registry_country` | string | No | Country of registration: NO for Norway or SE for Sweden. Allowed: `"NO"`, `"SE"`. | | `address` | string | No | Street address, including building or unit when applicable. | | `postal_code` | string | No | Postal code as text, preserving leading zeros. | | `city` | string | No | Postal town or city. | | `country` | string | No | Country associated with the address or record. | | `phone` | string | No | Phone number including its country calling code. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | | `product_lines` | array of [object](#response-item-data-product-lines) | No | Products or services agreed with this company, including quantity, price and billing frequency. | | `profile` | [object](#response-item-data-profile) | No | Generated or supplied company profile, with a summary and key facts. | ### response.item.data.product_lines[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `product_ref` | string | No | Product record ID. | | `name` | string | Yes | Display name. | | `description` | string | No | Descriptive text. | | `quantity` | number | No | Number of units. May be fractional when the product allows it. Minimum: 0. | | `unit` | string | No | Unit used for the quantity, such as hours or items. | | `unit_price_ore` | integer | No | Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only. | | `agreed_at` | number | No | Time the commercial terms were agreed, in Unix milliseconds. | | `agreed_deal_ref` | string | No | Deal record ID. | | `revenue_type` | string | No | Whether this amount is charged once or repeats monthly, quarterly or annually. Allowed: `"one_time"`, `"monthly"`, `"quarterly"`, `"annual"`. | | `start_date` | string | No | ISO date (YYYY-MM-DD) | | `end_date` | string | No | ISO date (YYYY-MM-DD) | ### response.item.data.profile | Field | Type | Required | Description | | --- | --- | --- | --- | | `summary` | string | No | Short summary of the source information. | | `highlights` | array of string | No | Key points extracted from the source information. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List companies](/developers/reference/customers/ListCompanies) - [Get company](/developers/reference/customers/GetCompany) - [Create company](/developers/reference/customers/CreateCompany) - [Update company](/developers/reference/customers/UpdateCompany) - [Delete company](/developers/reference/customers/DeleteCompany) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### First sync Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.UpsertCompany' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "name": "Example Consulting", "industry": "konsulent", "website": "https://example.com", "city": "Oslo" } }' ``` #### TypeScript ```typescript 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/customers.UpsertCompany", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "name": "Example Consulting", "industry": "konsulent", "website": "https://example.com", "city": "Oslo" } }), }); 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 = { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "name": "Example Consulting", "industry": "konsulent", "website": "https://example.com", "city": "Oslo" } } request = Request( "https://api.brigg.app/v1/operations/customers.UpsertCompany", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_company_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "name": "Example Consulting", "industry": "konsulent", "website": "https://example.com", "city": "Oslo" } }, "created": true } ``` ### Later sync The same external reference returns the same record ID. Use a new idempotency key for a later source change. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.UpsertCompany' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "name": "Example Consulting", "industry": "konsulent", "website": "https://example.com", "city": "Oslo" } }' ``` #### TypeScript ```typescript 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/customers.UpsertCompany", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "name": "Example Consulting", "industry": "konsulent", "website": "https://example.com", "city": "Oslo" } }), }); 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 = { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "name": "Example Consulting", "industry": "konsulent", "website": "https://example.com", "city": "Oslo" } } request = Request( "https://api.brigg.app/v1/operations/customers.UpsertCompany", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_company_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "name": "Example Consulting", "industry": "konsulent", "website": "https://example.com", "city": "Oslo" } }, "created": false } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "data": { "type": "object", "properties": { "name": { "type": "string", "description": "Company's display name; use org_number and registry_country for its registered identity." }, "domain": { "type": "string", "description": "Website hostname, without a scheme or path." }, "industry": { "type": "string", "enum": [ "bygg", "handel", "konsulent", "it", "helse", "restaurant", "eiendom", "transport", "finans", "utdanning", "industri", "offentlig", "annet" ], "description": "Industry classification. Send the stored enum value; the English label is for display only. Values: `bygg` — Construction; `handel` — Retail and wholesale; `konsulent` — Consulting; `it` — Information technology; `helse` — Healthcare; `restaurant` — Restaurants; `eiendom` — Real estate; `transport` — Transport; `finans` — Finance; `utdanning` — Education; `industri` — Manufacturing; `offentlig` — Public sector; `annet` — Other." }, "description": { "type": "string", "description": "Business description recorded for this company." }, "owner_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "website": { "type": "string", "description": "Company website URL, including https://." }, "org_number": { "type": "string", "description": "Organisation number from the company register, stored as text to preserve leading zeros." }, "registry_country": { "type": "string", "enum": [ "NO", "SE" ], "description": "Country of registration: NO for Norway or SE for Sweden." }, "address": { "type": "string", "description": "Street address, including building or unit when applicable." }, "postal_code": { "type": "string", "description": "Postal code as text, preserving leading zeros." }, "city": { "type": "string", "description": "Postal town or city." }, "country": { "type": "string", "description": "Country associated with the address or record." }, "phone": { "type": "string", "description": "Phone number including its country calling code." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, "product_lines": { "type": "array", "items": { "type": "object", "properties": { "product_ref": { "type": "string", "description": "Product record ID." }, "name": { "type": "string", "description": "Display name." }, "description": { "type": "string", "description": "Descriptive text." }, "quantity": { "type": "number", "minimum": 0, "description": "Number of units. May be fractional when the product allows it." }, "unit": { "type": "string", "description": "Unit used for the quantity, such as hours or items." }, "unit_price_ore": { "type": "integer", "description": "Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only." }, "agreed_at": { "type": "number", "description": "Time the commercial terms were agreed, in Unix milliseconds." }, "agreed_deal_ref": { "type": "string", "description": "Deal record ID." }, "revenue_type": { "type": "string", "enum": [ "one_time", "monthly", "quarterly", "annual" ], "description": "Whether this amount is charged once or repeats monthly, quarterly or annually." }, "start_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" }, "end_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" } }, "required": [ "name" ], "additionalProperties": false }, "description": "Products or services agreed with this company, including quantity, price and billing frequency." }, "profile": { "type": "object", "properties": { "summary": { "type": "string", "description": "Short summary of the source information." }, "highlights": { "type": "array", "items": { "type": "string" }, "description": "Key points extracted from the source information." } }, "additionalProperties": false, "description": "Generated or supplied company profile, with a summary and key facts." } }, "required": [ "name" ], "additionalProperties": false, "description": "The record's fields.", "title": "Company" }, "private": { "type": "boolean", "description": "Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance." }, "external_ref": { "type": "object", "description": "Permanent, case-sensitive source identity within this workspace, resource type and private/workspace scope. It is independent of API key rotation and retry receipt expiry.", "properties": { "namespace": { "type": "string", "minLength": 1, "description": "A stable name for the source system, such as crm-production." }, "id": { "type": "string", "minLength": 1, "description": "The record ID in that source system." } }, "required": [ "namespace", "id" ], "additionalProperties": false } }, "required": [ "external_ref", "data" ], "additionalProperties": false, "examples": [ { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "name": "Example Consulting", "industry": "konsulent", "website": "https://example.com", "city": "Oslo" } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:Company record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "name": { "type": "string", "description": "Company's display name; use org_number and registry_country for its registered identity." }, "domain": { "type": "string", "description": "Website hostname, without a scheme or path." }, "industry": { "type": "string", "enum": [ "bygg", "handel", "konsulent", "it", "helse", "restaurant", "eiendom", "transport", "finans", "utdanning", "industri", "offentlig", "annet" ], "description": "Industry classification. Send the stored enum value; the English label is for display only. Values: `bygg` — Construction; `handel` — Retail and wholesale; `konsulent` — Consulting; `it` — Information technology; `helse` — Healthcare; `restaurant` — Restaurants; `eiendom` — Real estate; `transport` — Transport; `finans` — Finance; `utdanning` — Education; `industri` — Manufacturing; `offentlig` — Public sector; `annet` — Other." }, "description": { "type": "string", "description": "Business description recorded for this company." }, "owner_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "website": { "type": "string", "description": "Company website URL, including https://." }, "org_number": { "type": "string", "description": "Organisation number from the company register, stored as text to preserve leading zeros." }, "registry_country": { "type": "string", "enum": [ "NO", "SE" ], "description": "Country of registration: NO for Norway or SE for Sweden." }, "address": { "type": "string", "description": "Street address, including building or unit when applicable." }, "postal_code": { "type": "string", "description": "Postal code as text, preserving leading zeros." }, "city": { "type": "string", "description": "Postal town or city." }, "country": { "type": "string", "description": "Country associated with the address or record." }, "phone": { "type": "string", "description": "Phone number including its country calling code." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, "product_lines": { "type": "array", "items": { "type": "object", "properties": { "product_ref": { "type": "string", "description": "Product record ID." }, "name": { "type": "string", "description": "Display name." }, "description": { "type": "string", "description": "Descriptive text." }, "quantity": { "type": "number", "minimum": 0, "description": "Number of units. May be fractional when the product allows it." }, "unit": { "type": "string", "description": "Unit used for the quantity, such as hours or items." }, "unit_price_ore": { "type": "integer", "description": "Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only." }, "agreed_at": { "type": "number", "description": "Time the commercial terms were agreed, in Unix milliseconds." }, "agreed_deal_ref": { "type": "string", "description": "Deal record ID." }, "revenue_type": { "type": "string", "enum": [ "one_time", "monthly", "quarterly", "annual" ], "description": "Whether this amount is charged once or repeats monthly, quarterly or annually." }, "start_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" }, "end_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" } }, "required": [ "name" ], "additionalProperties": false }, "description": "Products or services agreed with this company, including quantity, price and billing frequency." }, "profile": { "type": "object", "properties": { "summary": { "type": "string", "description": "Short summary of the source information." }, "highlights": { "type": "array", "items": { "type": "string" }, "description": "Key points extracted from the source information." } }, "additionalProperties": false, "description": "Generated or supplied company profile, with a summary and key facts." } }, "required": [ "name" ], "additionalProperties": false, "description": "The record's fields.", "title": "Company" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "CompanyRecord" }, "created": { "type": "boolean", "description": "True when this external reference created a record; false when it matched an existing record." } }, "required": [ "item", "created" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_company_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "name": "Example Consulting", "industry": "konsulent", "website": "https://example.com", "city": "Oslo" } }, "created": true } ] } ``` --- # Get indexed company Read a Norwegian company's registry details, board and management roles, annual financial figures and known websites. POST https://api.brigg.app/v1/operations/customers.GetIndexedCompany ## Access & visibility Allow `customers.GetIndexedCompany` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `org_number` | string | Yes | Nine-digit Norwegian organisation number. Pattern: `^\d{9}$`. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `company` | [object](#response-company) | Yes | Company-register information for the requested company. | | `nace_labels` | array of string | Yes | Human-readable labels for the industry's classification codes. | | `kommune_name` | null or string | Yes | Municipality display name. | | `roles` | array of [object](#response-roles) | Yes | Roles recorded by the company register for this person or organization. | | `financials` | array of [object](#response-financials) | Yes | Financial reports returned for this company. | | `domains` | array of [object](#response-domains) | Yes | Web domains associated with the company. | | `chunks` | array of [object](#response-chunks) | Yes | Number or collection of indexed source chunks returned for this source. | | `underenheter` | array of [object](#response-underenheter) | Yes | Registered business units belonging to the company. | | `events` | array of [object](#response-events) | Yes | Recorded changes or source events associated with the company. | ### response.company | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Display name. | | `raw` | JSON value | Yes | Original company-register facts. Prefer the named, normalised fields for portable integrations. | | `created_at` | number | Yes | Creation time in Unix milliseconds. | | `org_number` | string | Yes | Nine-digit Norwegian organisation number. | | `updated_at` | number | Yes | Last update time in Unix milliseconds. | | `entity_kind` | string | Yes | Whether this entry represents a main entity or business unit. | | `parent_org_number` | null or string | Yes | Organization number of the parent entity. | | `name_key` | string | Yes | Normalized lookup key used for this person's name; not a unique person ID. | | `org_form` | null or string | Yes | Legal organization form code used by the register. | | `nace_codes` | JSON value | Yes | Industry classification codes recorded by the company register. | | `employees` | null or number | Yes | Employee count reported by the source. | | `has_registered_employees` | null or boolean | Yes | Whether the register reports employees for this company. | | `kommune_number` | null or string | Yes | Norwegian municipality code used to filter companies. | | `postal_code` | null or string | Yes | Postal code as text, preserving leading zeros. | | `city` | null or string | Yes | Postal town or city. | | `address_json` | JSON value | Yes | Structured address supplied by the company register; keys vary by register. | | `founded_date` | null or string | Yes | Company founding date from the register. | | `registered_date` | null or string | Yes | Date the company was registered. | | `website_raw` | null or string | Yes | Website value as supplied by the original source. | | `email` | null or string | Yes | Email address. | | `phone` | null or string | Yes | Phone number including its country calling code. | | `linkedin_url` | null or string | Yes | Public LinkedIn profile URL for the person or company. | | `share_capital` | null or number | Yes | Share capital reported by the company register. | | `in_konsern` | null or boolean | Yes | Whether the company belongs to a corporate group. | | `bankrupt` | boolean | Yes | Whether the register marks the company as bankrupt. Allowed: `false`, `true`. | | `winding_down` | boolean | Yes | Whether the register marks the company as winding down. Allowed: `false`, `true`. | | `forced_liquidation` | boolean | Yes | Whether the register marks the company for compulsory liquidation. Allowed: `false`, `true`. | | `vat_registered` | null or boolean | Yes | Whether the company is registered for VAT. | | `in_foretaksregisteret` | null or boolean | Yes | Whether the company is registered in Norway's Register of Business Enterprises. | | `registry_deleted_at` | null or number | Yes | Recorded event time in Unix milliseconds. | | `registry_updated_at` | null or number | Yes | Recorded event time in Unix milliseconds. | | `profile_text` | null or string | Yes | Text representation of the company profile used for discovery. | | `profile_embedded_at` | null or number | Yes | Recorded event time in Unix milliseconds. | | `profile_embed_attempts` | number | Yes | Number of recorded attempts for this background activity. | | `profile_embed_next_at` | null or number | Yes | Recorded event time in Unix milliseconds. | | `financials_fetched_at` | null or number | Yes | Recorded event time in Unix milliseconds. | | `financials_attempts` | number | Yes | Number of recorded attempts for this background activity. | | `financials_next_at` | null or number | Yes | Recorded event time in Unix milliseconds. | | `latest_revenue` | null or number | Yes | Revenue from the latest available financial report. | | `roles_synced_at` | null or number | Yes | Recorded event time in Unix milliseconds. | | `discovery_status` | string | Yes | Current state of company website discovery. | | `discovery_attempts` | number | Yes | Number of recorded attempts for this background activity. | | `discovery_next_at` | null or number | Yes | Recorded event time in Unix milliseconds. | ### response.roles[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `ord` | number | Yes | Ordering value of this item within the returned collection. | | `role_group` | string | Yes | Norwegian register role group, for example STYR (board) or DAGL (general management). Preserve unknown source codes. | | `role_code` | string | Yes | Norwegian register role code, for example LEDE (board chair), MEDL (board member), VARA (deputy board member) or DAGL (general manager). This response does not include a separate display label; preserve unknown codes. | | `holder_key` | string | Yes | Register's identifier for the role holder. | | `holder_name` | null or string | Yes | Name of the person or organization holding the role. | | `birth_date` | null or string | Yes | Birth date in YYYY-MM-DD format, or null when the source register does not supply one. A name match alone does not establish identity. | | `rank` | null or number | Yes | Relative rank within these search results, not a percentage. | | `resigned` | boolean | Yes | Whether the register reports this role as resigned. Allowed: `false`, `true`. | | `last_changed` | null or string | Yes | Last change timestamp supplied by the role register. | ### response.financials[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `fiscal_year` | number | Yes | Fiscal year to which these financial figures apply. | | `accounting_type` | null or string | Yes | Accounting/report category used by the source. | | `currency` | null or string | Yes | Three-letter currency code, such as NOK, SEK or EUR. | | `revenue` | null or number | Yes | Revenue in the source financial report's units. | | `operating_result` | null or number | Yes | Operating profit or loss in the source financial report's units. | | `result_before_tax` | null or number | Yes | Profit or loss before tax in the source financial report's units. | | `net_result` | null or number | Yes | Net profit or loss in the source financial report's units. | | `equity` | null or number | Yes | Total equity in the source financial report's units. | | `debt_short` | null or number | Yes | Short-term debt in the source financial report's units. | | `debt_long` | null or number | Yes | Long-term debt in the source financial report's units. | | `assets_total` | null or number | Yes | Total assets in the source financial report's units. | | `fetched_at` | number | Yes | Recorded event time in Unix milliseconds. | ### response.domains[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `domain` | string | Yes | Website hostname, without a scheme or path. | | `link_source` | string | Yes | Source of the association between the company and website. | | `link_confidence` | string | Yes | Confidence assigned to the company-to-website association; not a percentage unless the source specifies one. | | `is_primary` | boolean | Yes | Whether this is the primary website associated with the company. Allowed: `false`, `true`. | | `scrape_status` | null or string | Yes | Most recently recorded website-fetch status. | | `last_scraped_at` | null or number | Yes | Recorded event time in Unix milliseconds. | | `favicon_url` | string | Yes | Website icon URL discovered for the company. | | `emails` | array of string | Yes | Additional email addresses. | | `phones` | array of string | Yes | Phone numbers discovered for the company. | | `social_links` | map of string | Yes | Public social-profile links discovered for the company. | | `title` | null or string | Yes | Display title. | | `description` | null or string | Yes | Descriptive text. | | `orgnrs_on_site` | array of string | Yes | Organization numbers found on the company's website. | | `last_error` | null or string | Yes | Most recent website-fetch failure, or null when none is recorded. | | `snapshot` | null or [object](#response-domains-snapshot) | Yes | Source facts captured for this result. | ### response.domains[].snapshot | Field | Type | Required | Description | | --- | --- | --- | --- | | `scraped_at` | number | Yes | Recorded event time in Unix milliseconds. | | `formats` | array of string | Yes | Supported data formats for this operation. | | `title` | null or string | Yes | Display title. | | `final_url` | null or string | Yes | Final website URL after following redirects. | ### response.chunks[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Category identifying which variant of this model applies. | | `total` | number | Yes | Number of source records covered by this preview or search. | | `embedded` | number | Yes | Whether the source has a recorded search embedding. | ### response.underenheter[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `org_number` | string | Yes | Official organization number as text; preserve leading zeros. | | `name` | string | Yes | Display name. | | `city` | null or string | Yes | Postal town or city. | | `employees` | null or number | Yes | Employee count reported by the source. | ### response.events[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Category identifying which variant of this model applies. | | `old_value` | null or string | Yes | Value before the recorded change. | | `new_value` | null or string | Yes | Value after the recorded change. | | `detected_at` | number | Yes | Recorded event time in Unix milliseconds. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.GetIndexedCompany' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "org_number": "999999999" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.GetIndexedCompany", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "org_number": "999999999" }), }); 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 payload = { "org_number": "999999999" } request = Request( "https://api.brigg.app/v1/operations/customers.GetIndexedCompany", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "company": { "name": "Northstar Consulting AS", "raw": null, "created_at": 1794301200000, "org_number": "999999999", "updated_at": 1794301200000, "entity_kind": "hovedenhet", "parent_org_number": null, "name_key": "alex morgan", "org_form": "AS", "nace_codes": null, "employees": null, "has_registered_employees": null, "kommune_number": "0301", "postal_code": null, "city": null, "address_json": null, "founded_date": null, "registered_date": null, "website_raw": "https://example.com", "email": null, "phone": null, "linkedin_url": "https://www.linkedin.com/company/example", "share_capital": null, "in_konsern": null, "bankrupt": false, "winding_down": false, "forced_liquidation": false, "vat_registered": null, "in_foretaksregisteret": null, "registry_deleted_at": null, "registry_updated_at": null, "profile_text": "Consulting services for small businesses.", "profile_embedded_at": null, "profile_embed_attempts": 1, "profile_embed_next_at": null, "financials_fetched_at": null, "financials_attempts": 1, "financials_next_at": null, "latest_revenue": null, "roles_synced_at": null, "discovery_status": "done", "discovery_attempts": 1, "discovery_next_at": null }, "nace_labels": [ "IT consultancy activities" ], "kommune_name": "Oslo", "roles": [], "financials": [], "domains": [], "chunks": [], "underenheter": [], "events": [] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "org_number": { "type": "string", "pattern": "^\\d{9}$", "description": "Nine-digit Norwegian organisation number." } }, "required": [ "org_number" ], "additionalProperties": false, "examples": [ { "org_number": "999999999" } ] } ``` ```json-schema-response { "title": "GetIndexedCompany", "type": "object", "properties": { "company": { "type": "object", "properties": { "name": { "type": "string", "description": "Display name." }, "raw": { "description": "Original company-register facts. Prefer the named, normalised fields for portable integrations." }, "created_at": { "type": "number", "description": "Creation time in Unix milliseconds." }, "org_number": { "type": "string", "description": "Nine-digit Norwegian organisation number." }, "updated_at": { "type": "number", "description": "Last update time in Unix milliseconds." }, "entity_kind": { "type": "string", "description": "Whether this entry represents a main entity or business unit." }, "parent_org_number": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Organization number of the parent entity." }, "name_key": { "type": "string", "description": "Normalized lookup key used for this person's name; not a unique person ID." }, "org_form": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Legal organization form code used by the register." }, "nace_codes": { "description": "Industry classification codes recorded by the company register." }, "employees": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Employee count reported by the source." }, "has_registered_employees": { "anyOf": [ { "type": "null" }, { "type": "boolean", "const": false }, { "type": "boolean", "const": true } ], "description": "Whether the register reports employees for this company." }, "kommune_number": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Norwegian municipality code used to filter companies." }, "postal_code": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Postal code as text, preserving leading zeros." }, "city": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Postal town or city." }, "address_json": { "description": "Structured address supplied by the company register; keys vary by register." }, "founded_date": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Company founding date from the register." }, "registered_date": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Date the company was registered." }, "website_raw": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Website value as supplied by the original source." }, "email": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Email address." }, "phone": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Phone number including its country calling code." }, "linkedin_url": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Public LinkedIn profile URL for the person or company." }, "share_capital": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Share capital reported by the company register." }, "in_konsern": { "anyOf": [ { "type": "null" }, { "type": "boolean", "const": false }, { "type": "boolean", "const": true } ], "description": "Whether the company belongs to a corporate group." }, "bankrupt": { "type": "boolean", "enum": [ false, true ], "description": "Whether the register marks the company as bankrupt." }, "winding_down": { "type": "boolean", "enum": [ false, true ], "description": "Whether the register marks the company as winding down." }, "forced_liquidation": { "type": "boolean", "enum": [ false, true ], "description": "Whether the register marks the company for compulsory liquidation." }, "vat_registered": { "anyOf": [ { "type": "null" }, { "type": "boolean", "const": false }, { "type": "boolean", "const": true } ], "description": "Whether the company is registered for VAT." }, "in_foretaksregisteret": { "anyOf": [ { "type": "null" }, { "type": "boolean", "const": false }, { "type": "boolean", "const": true } ], "description": "Whether the company is registered in Norway's Register of Business Enterprises." }, "registry_deleted_at": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Recorded event time in Unix milliseconds." }, "registry_updated_at": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Recorded event time in Unix milliseconds." }, "profile_text": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Text representation of the company profile used for discovery." }, "profile_embedded_at": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Recorded event time in Unix milliseconds." }, "profile_embed_attempts": { "type": "number", "description": "Number of recorded attempts for this background activity." }, "profile_embed_next_at": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Recorded event time in Unix milliseconds." }, "financials_fetched_at": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Recorded event time in Unix milliseconds." }, "financials_attempts": { "type": "number", "description": "Number of recorded attempts for this background activity." }, "financials_next_at": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Recorded event time in Unix milliseconds." }, "latest_revenue": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Revenue from the latest available financial report." }, "roles_synced_at": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Recorded event time in Unix milliseconds." }, "discovery_status": { "type": "string", "description": "Current state of company website discovery." }, "discovery_attempts": { "type": "number", "description": "Number of recorded attempts for this background activity." }, "discovery_next_at": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Recorded event time in Unix milliseconds." } }, "required": [ "name", "raw", "created_at", "org_number", "updated_at", "entity_kind", "parent_org_number", "name_key", "org_form", "nace_codes", "employees", "has_registered_employees", "kommune_number", "postal_code", "city", "address_json", "founded_date", "registered_date", "website_raw", "email", "phone", "linkedin_url", "share_capital", "in_konsern", "bankrupt", "winding_down", "forced_liquidation", "vat_registered", "in_foretaksregisteret", "registry_deleted_at", "registry_updated_at", "profile_text", "profile_embedded_at", "profile_embed_attempts", "profile_embed_next_at", "financials_fetched_at", "financials_attempts", "financials_next_at", "latest_revenue", "roles_synced_at", "discovery_status", "discovery_attempts", "discovery_next_at" ], "additionalProperties": false, "description": "Company-register information for the requested company." }, "nace_labels": { "type": "array", "items": { "type": "string" }, "description": "Human-readable labels for the industry's classification codes." }, "kommune_name": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Municipality display name." }, "roles": { "type": "array", "items": { "type": "object", "properties": { "ord": { "type": "number", "description": "Ordering value of this item within the returned collection." }, "role_group": { "type": "string", "description": "Norwegian register role group, for example STYR (board) or DAGL (general management). Preserve unknown source codes." }, "role_code": { "type": "string", "description": "Norwegian register role code, for example LEDE (board chair), MEDL (board member), VARA (deputy board member) or DAGL (general manager). This response does not include a separate display label; preserve unknown codes." }, "holder_key": { "type": "string", "description": "Register's identifier for the role holder." }, "holder_name": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Name of the person or organization holding the role." }, "birth_date": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Birth date in YYYY-MM-DD format, or null when the source register does not supply one. A name match alone does not establish identity." }, "rank": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Relative rank within these search results, not a percentage." }, "resigned": { "type": "boolean", "enum": [ false, true ], "description": "Whether the register reports this role as resigned." }, "last_changed": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Last change timestamp supplied by the role register." } }, "required": [ "ord", "role_group", "role_code", "holder_key", "holder_name", "birth_date", "rank", "resigned", "last_changed" ], "additionalProperties": false }, "description": "Roles recorded by the company register for this person or organization." }, "financials": { "type": "array", "items": { "type": "object", "properties": { "fiscal_year": { "type": "number", "description": "Fiscal year to which these financial figures apply." }, "accounting_type": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Accounting/report category used by the source." }, "currency": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Three-letter currency code, such as NOK, SEK or EUR." }, "revenue": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Revenue in the source financial report's units." }, "operating_result": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Operating profit or loss in the source financial report's units." }, "result_before_tax": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Profit or loss before tax in the source financial report's units." }, "net_result": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Net profit or loss in the source financial report's units." }, "equity": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Total equity in the source financial report's units." }, "debt_short": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Short-term debt in the source financial report's units." }, "debt_long": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Long-term debt in the source financial report's units." }, "assets_total": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Total assets in the source financial report's units." }, "fetched_at": { "type": "number", "description": "Recorded event time in Unix milliseconds." } }, "required": [ "fiscal_year", "accounting_type", "currency", "revenue", "operating_result", "result_before_tax", "net_result", "equity", "debt_short", "debt_long", "assets_total", "fetched_at" ], "additionalProperties": false }, "description": "Financial reports returned for this company." }, "domains": { "type": "array", "items": { "type": "object", "properties": { "domain": { "type": "string", "description": "Website hostname, without a scheme or path." }, "link_source": { "type": "string", "description": "Source of the association between the company and website." }, "link_confidence": { "type": "string", "description": "Confidence assigned to the company-to-website association; not a percentage unless the source specifies one." }, "is_primary": { "type": "boolean", "enum": [ false, true ], "description": "Whether this is the primary website associated with the company." }, "scrape_status": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Most recently recorded website-fetch status." }, "last_scraped_at": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Recorded event time in Unix milliseconds." }, "favicon_url": { "type": "string", "description": "Website icon URL discovered for the company." }, "emails": { "type": "array", "items": { "type": "string" }, "description": "Additional email addresses." }, "phones": { "type": "array", "items": { "type": "string" }, "description": "Phone numbers discovered for the company." }, "social_links": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Public social-profile links discovered for the company." }, "title": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Display title." }, "description": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Descriptive text." }, "orgnrs_on_site": { "type": "array", "items": { "type": "string" }, "description": "Organization numbers found on the company's website." }, "last_error": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Most recent website-fetch failure, or null when none is recorded." }, "snapshot": { "anyOf": [ { "type": "null" }, { "type": "object", "properties": { "scraped_at": { "type": "number", "description": "Recorded event time in Unix milliseconds." }, "formats": { "type": "array", "items": { "type": "string" }, "description": "Supported data formats for this operation." }, "title": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Display title." }, "final_url": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Final website URL after following redirects." } }, "required": [ "scraped_at", "formats", "title", "final_url" ], "additionalProperties": false } ], "description": "Source facts captured for this result." } }, "required": [ "domain", "link_source", "link_confidence", "is_primary", "scrape_status", "last_scraped_at", "favicon_url", "emails", "phones", "social_links", "title", "description", "orgnrs_on_site", "last_error", "snapshot" ], "additionalProperties": false }, "description": "Web domains associated with the company." }, "chunks": { "type": "array", "items": { "type": "object", "properties": { "kind": { "type": "string", "description": "Category identifying which variant of this model applies." }, "total": { "type": "number", "description": "Number of source records covered by this preview or search." }, "embedded": { "type": "number", "description": "Whether the source has a recorded search embedding." } }, "required": [ "kind", "total", "embedded" ], "additionalProperties": false }, "description": "Number or collection of indexed source chunks returned for this source." }, "underenheter": { "type": "array", "items": { "type": "object", "properties": { "org_number": { "type": "string", "description": "Official organization number as text; preserve leading zeros." }, "name": { "type": "string", "description": "Display name." }, "city": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Postal town or city." }, "employees": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Employee count reported by the source." } }, "required": [ "org_number", "name", "city", "employees" ], "additionalProperties": false }, "description": "Registered business units belonging to the company." }, "events": { "type": "array", "items": { "type": "object", "properties": { "kind": { "type": "string", "description": "Category identifying which variant of this model applies." }, "old_value": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Value before the recorded change." }, "new_value": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Value after the recorded change." }, "detected_at": { "type": "number", "description": "Recorded event time in Unix milliseconds." } }, "required": [ "kind", "old_value", "new_value", "detected_at" ], "additionalProperties": false }, "description": "Recorded changes or source events associated with the company." } }, "required": [ "company", "nace_labels", "kommune_name", "roles", "financials", "domains", "chunks", "underenheter", "events" ], "additionalProperties": false, "examples": [ { "company": { "name": "Northstar Consulting AS", "raw": null, "created_at": 1794301200000, "org_number": "999999999", "updated_at": 1794301200000, "entity_kind": "hovedenhet", "parent_org_number": null, "name_key": "alex morgan", "org_form": "AS", "nace_codes": null, "employees": null, "has_registered_employees": null, "kommune_number": "0301", "postal_code": null, "city": null, "address_json": null, "founded_date": null, "registered_date": null, "website_raw": "https://example.com", "email": null, "phone": null, "linkedin_url": "https://www.linkedin.com/company/example", "share_capital": null, "in_konsern": null, "bankrupt": false, "winding_down": false, "forced_liquidation": false, "vat_registered": null, "in_foretaksregisteret": null, "registry_deleted_at": null, "registry_updated_at": null, "profile_text": "Consulting services for small businesses.", "profile_embedded_at": null, "profile_embed_attempts": 1, "profile_embed_next_at": null, "financials_fetched_at": null, "financials_attempts": 1, "financials_next_at": null, "latest_revenue": null, "roles_synced_at": null, "discovery_status": "done", "discovery_attempts": 1, "discovery_next_at": null }, "nace_labels": [ "IT consultancy activities" ], "kommune_name": "Oslo", "roles": [], "financials": [], "domains": [], "chunks": [], "underenheter": [], "events": [] } ] } ``` --- # Search company index Search the Norwegian company index using text, registry filters or a similar company's organisation number. Results include registry facts and matching companies. POST https://api.brigg.app/v1/operations/customers.SearchCompanyIndex ## Access & visibility Allow `customers.SearchCompanyIndex` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `query` | string | No | Free-text search over company names, registry profiles and scraped site content (keyword + meaning). Omit for a pure filter listing. At least 1 character. At most 400 characters. | | `similar_to` | string | No | Find companies SIMILAR to this one (9-digit org number) — its indexed profile is the query. Combine with filters (e.g. kommune) to scope the result. Pattern: `^\d{9}$`. | | `nace_prefix` | array of string | No | SN2025 NACE code prefixes, e.g. ['62'] for IT services or ['69.20'] for accounting. A company matches when any of its codes starts with a prefix. Checked against the register's own SN2025 vocabulary — a retired SN2007 code is REFUSED rather than silently matching nothing, so when you are unsure of the code, search by industry name in `query` instead. At most 10 items. | | `kommune` | array of string | No | Norwegian kommune numbers (4 digits), e.g. ['0301'] for Oslo. Checked against the register's current list — the 2020 and 2024 reforms renumbered municipalities, and a pre-reform number is REFUSED rather than matching nothing. At most 20 items. | | `employees_min` | integer | No | Minimum employee count for matching companies. Minimum: 0. | | `employees_max` | integer | No | Maximum employee count for matching companies. Minimum: 0. | | `founded_from` | string | No | Founded on/after this ISO date (YYYY-MM-DD). Pattern: `^\d{4}-\d{2}-\d{2}$`. | | `founded_to` | string | No | Founded on/before this ISO date (YYYY-MM-DD). Pattern: `^\d{4}-\d{2}-\d{2}$`. | | `org_form` | array of string | No | Organisation forms, e.g. ['AS'] or ['AS','ASA']. At most 10 items. | | `has_website` | boolean | No | true = only companies with a linked website. | | `limit` | integer | No | Number of results to request per page. Maximum: 25. Greater than 0. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `hits` | array of [CompanySearchHit](#companysearchhit-response-hits) | Yes | Matching company records, in the returned search order. | ### CompanySearchHit · response.hits[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `org_number` | string | Yes | Official organization number as text; preserve leading zeros. | | `name` | string | Yes | Display name. | | `org_form` | null or string | Yes | Legal organization form code used by the register. | | `nace` | array of string | Yes | Industry classification codes supplied by the register. | | `industry_label` | null or string | Yes | Human-readable industry classification. | | `kommune` | null or string | Yes | Norwegian municipality code supplied by the register. | | `city` | null or string | Yes | Postal town or city. | | `employees` | null or number | Yes | Employee count reported by the source. | | `founded_date` | null or string | Yes | Company founding date from the register. | | `latest_revenue` | null or [object](#response-hits-latest-revenue) | Yes | Revenue from the latest available financial report. | | `domains` | array of string | Yes | Web domains associated with the company. | | `emails` | array of string | Yes | Additional email addresses. | | `daglig_leder` | null or string | Yes | Managing director reported by the Norwegian register. | | `score` | number | Yes | Score assigned to this result. Use the operation's scale and constraints when interpreting it. | | `channels` | array of string | Yes | Channels contributing to this result or selected for this operation. Each item: `"keyword"`, `"semantic"`. | | `snippet` | string | Yes | A short excerpt showing why the result matched. | ### response.hits[].latest_revenue | Field | Type | Required | Description | | --- | --- | --- | --- | | `fiscal_year` | number | Yes | Fiscal year to which these financial figures apply. | | `revenue` | null or number | Yes | Revenue in the source financial report's units. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.SearchCompanyIndex' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{}' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.SearchCompanyIndex", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/customers.SearchCompanyIndex", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "hits": [ { "org_number": "999999999", "name": "Northstar Consulting AS", "org_form": "AS", "nace": [ "62.020" ], "industry_label": "IT consulting", "kommune": "0301", "city": null, "employees": null, "founded_date": null, "latest_revenue": null, "domains": [], "emails": [], "daglig_leder": "Alex Morgan", "score": 1, "channels": [], "snippet": "IT consulting and onboarding services." } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "query": { "type": "string", "minLength": 1, "maxLength": 400, "description": "Free-text search over company names, registry profiles and scraped site content (keyword + meaning). Omit for a pure filter listing." }, "similar_to": { "type": "string", "pattern": "^\\d{9}$", "description": "Find companies SIMILAR to this one (9-digit org number) — its indexed profile is the query. Combine with filters (e.g. kommune) to scope the result." }, "nace_prefix": { "type": "array", "items": { "type": "string", "minLength": 2, "maxLength": 8 }, "maxItems": 10, "description": "SN2025 NACE code prefixes, e.g. ['62'] for IT services or ['69.20'] for accounting. A company matches when any of its codes starts with a prefix. Checked against the register's own SN2025 vocabulary — a retired SN2007 code is REFUSED rather than silently matching nothing, so when you are unsure of the code, search by industry name in `query` instead." }, "kommune": { "type": "array", "items": { "type": "string", "pattern": "^\\d{4}$" }, "maxItems": 20, "description": "Norwegian kommune numbers (4 digits), e.g. ['0301'] for Oslo. Checked against the register's current list — the 2020 and 2024 reforms renumbered municipalities, and a pre-reform number is REFUSED rather than matching nothing." }, "employees_min": { "type": "integer", "minimum": 0, "description": "Minimum employee count for matching companies." }, "employees_max": { "type": "integer", "minimum": 0, "description": "Maximum employee count for matching companies." }, "founded_from": { "type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$", "description": "Founded on/after this ISO date (YYYY-MM-DD)." }, "founded_to": { "type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$", "description": "Founded on/before this ISO date (YYYY-MM-DD)." }, "org_form": { "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 10 }, "maxItems": 10, "description": "Organisation forms, e.g. ['AS'] or ['AS','ASA']." }, "has_website": { "type": "boolean", "description": "true = only companies with a linked website." }, "limit": { "type": "integer", "exclusiveMinimum": 0, "maximum": 25, "description": "Number of results to request per page." } }, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "hits": { "type": "array", "items": { "title": "CompanySearchHit", "type": "object", "properties": { "org_number": { "type": "string", "description": "Official organization number as text; preserve leading zeros." }, "name": { "type": "string", "description": "Display name." }, "org_form": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Legal organization form code used by the register." }, "nace": { "type": "array", "items": { "type": "string" }, "description": "Industry classification codes supplied by the register." }, "industry_label": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Human-readable industry classification." }, "kommune": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Norwegian municipality code supplied by the register." }, "city": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Postal town or city." }, "employees": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Employee count reported by the source." }, "founded_date": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Company founding date from the register." }, "latest_revenue": { "anyOf": [ { "type": "null" }, { "type": "object", "properties": { "fiscal_year": { "type": "number", "description": "Fiscal year to which these financial figures apply." }, "revenue": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Revenue in the source financial report's units." } }, "required": [ "fiscal_year", "revenue" ], "additionalProperties": false } ], "description": "Revenue from the latest available financial report." }, "domains": { "type": "array", "items": { "type": "string" }, "description": "Web domains associated with the company." }, "emails": { "type": "array", "items": { "type": "string" }, "description": "Additional email addresses." }, "daglig_leder": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Managing director reported by the Norwegian register." }, "score": { "type": "number", "description": "Score assigned to this result. Use the operation's scale and constraints when interpreting it." }, "channels": { "type": "array", "items": { "type": "string", "enum": [ "keyword", "semantic" ] }, "description": "Channels contributing to this result or selected for this operation." }, "snippet": { "type": "string", "description": "A short excerpt showing why the result matched." } }, "required": [ "org_number", "name", "org_form", "nace", "industry_label", "kommune", "city", "employees", "founded_date", "latest_revenue", "domains", "emails", "daglig_leder", "score", "channels", "snippet" ], "additionalProperties": false }, "description": "Matching company records, in the returned search order." } }, "required": [ "hits" ], "additionalProperties": false, "examples": [ { "hits": [ { "org_number": "999999999", "name": "Northstar Consulting AS", "org_form": "AS", "nace": [ "62.020" ], "industry_label": "IT consulting", "kommune": "0301", "city": null, "employees": null, "founded_date": null, "latest_revenue": null, "domains": [], "emails": [], "daglig_leder": "Alex Morgan", "score": 1, "channels": [], "snippet": "IT consulting and onboarding services." } ] } ] } ``` --- # Search person roles Find people by name and read their roles in the Norwegian company register. Optionally restrict returned roles to one company; names alone do not establish identity. POST https://api.brigg.app/v1/operations/customers.SearchPersonRoles ## Access & visibility Allow `customers.SearchPersonRoles` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `name` | string | Yes | Case-insensitive name substring in the Norwegian company index, for example Kari Nordmann. This searches registered role holders, not your workspace's Person records. At least 2 characters. At most 200 characters. | | `org_number` | string | No | Nine-digit Norwegian organization number. Restricts returned roles to that company; a Brigg Company record ID is not accepted. Pattern: `^\d{9}$`. | ## Verify a registry match before using it This reads Brigg's index of the Norwegian company register, not the workspace contact list. Data reflects the index's most recent import and is not a live identity verification. Names are not unique: compare the reported name, birth date when available, organization number and role. A null birth date is unknown, not a mismatch. The call selects up to ten matching people before restricting their roles to org_number. An empty result therefore does not prove a person holds no role. Use a more specific name and [Get indexed company](/developers/reference/customers/GetIndexedCompany) to inspect one company's indexed roles. There is no paging parameter for this operation. Use [List people](/developers/reference/customers/ListPeople) when looking for your own customer contacts. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `roles` | array of [PersonRegistryRoles](#personregistryroles-response-roles) | Yes | Up to ten name-matching people, ordered by name similarity, with their registered roles. A company filter removes people without a matching role; there is no cursor or exhaustive-search guarantee. | ### PersonRegistryRoles · response.roles[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `person_key` | string | Yes | Opaque register-person key. Keep it for comparing hits; it is not a Brigg Person ID or a government identity number. | | `full_name` | string | Yes | Full name reported for this person. | | `birth_date` | null or string | Yes | Birth date in YYYY-MM-DD format, or null when the source register does not supply one. A name match alone does not establish identity. | | `roles` | array of [object](#response-roles-roles) | Yes | Roles held by this person in the indexed register, optionally restricted to org_number. Can be empty without a company filter. | ### response.roles[].roles[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `org_number` | string | Yes | Official organization number as text; preserve leading zeros. | | `company_name` | null or string | Yes | Registered company name. | | `role_group` | string | Yes | Norwegian register role group, for example STYR (board) or DAGL (general management). Preserve unknown source codes. | | `role_code` | string | Yes | Norwegian register role code, for example LEDE (board chair), MEDL (board member), VARA (deputy board member) or DAGL (general manager). This response does not include a separate display label; preserve unknown codes. | | `resigned` | boolean | Yes | Whether the register reports this role as resigned. Allowed: `false`, `true`. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [Get indexed company](/developers/reference/customers/GetIndexedCompany) - [Search company index](/developers/reference/customers/SearchCompanyIndex) - [List people](/developers/reference/customers/ListPeople) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Find a person's role in one company Names, dates and organization numbers below are fictional. Check the returned role instead of trusting the name alone. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.SearchPersonRoles' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "name": "Kari Nordmann", "org_number": "999999999" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.SearchPersonRoles", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "name": "Kari Nordmann", "org_number": "999999999" }), }); 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 payload = { "name": "Kari Nordmann", "org_number": "999999999" } request = Request( "https://api.brigg.app/v1/operations/customers.SearchPersonRoles", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "roles": [ { "person_key": "registry_person_kari", "full_name": "Kari Nordmann", "birth_date": "1980-04-12", "roles": [ { "org_number": "999999999", "company_name": "Northstar Consulting AS", "role_group": "STYR", "role_code": "LEDE", "resigned": false } ] } ] } ``` ### No matching role returned This is a successful lookup, not proof of absence from the registry. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.SearchPersonRoles' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "name": "Kari Nordmann", "org_number": "999999999" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.SearchPersonRoles", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "name": "Kari Nordmann", "org_number": "999999999" }), }); 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 payload = { "name": "Kari Nordmann", "org_number": "999999999" } request = Request( "https://api.brigg.app/v1/operations/customers.SearchPersonRoles", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "roles": [] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "name": { "type": "string", "minLength": 2, "maxLength": 200, "description": "Case-insensitive name substring in the Norwegian company index, for example Kari Nordmann. This searches registered role holders, not your workspace's Person records." }, "org_number": { "type": "string", "pattern": "^\\d{9}$", "description": "Nine-digit Norwegian organization number. Restricts returned roles to that company; a Brigg Company record ID is not accepted." } }, "required": [ "name" ], "additionalProperties": false, "examples": [ { "name": "Kari Nordmann", "org_number": "999999999" } ] } ``` ```json-schema-response { "type": "object", "properties": { "roles": { "type": "array", "items": { "title": "PersonRegistryRoles", "type": "object", "properties": { "person_key": { "type": "string", "description": "Opaque register-person key. Keep it for comparing hits; it is not a Brigg Person ID or a government identity number." }, "full_name": { "type": "string", "description": "Full name reported for this person." }, "birth_date": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Birth date in YYYY-MM-DD format, or null when the source register does not supply one. A name match alone does not establish identity." }, "roles": { "type": "array", "items": { "type": "object", "properties": { "org_number": { "type": "string", "description": "Official organization number as text; preserve leading zeros." }, "company_name": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Registered company name." }, "role_group": { "type": "string", "description": "Norwegian register role group, for example STYR (board) or DAGL (general management). Preserve unknown source codes." }, "role_code": { "type": "string", "description": "Norwegian register role code, for example LEDE (board chair), MEDL (board member), VARA (deputy board member) or DAGL (general manager). This response does not include a separate display label; preserve unknown codes." }, "resigned": { "type": "boolean", "enum": [ false, true ], "description": "Whether the register reports this role as resigned." } }, "required": [ "org_number", "company_name", "role_group", "role_code", "resigned" ], "additionalProperties": false }, "description": "Roles held by this person in the indexed register, optionally restricted to org_number. Can be empty without a company filter." } }, "required": [ "person_key", "full_name", "birth_date", "roles" ], "additionalProperties": false }, "description": "Up to ten name-matching people, ordered by name similarity, with their registered roles. A company filter removes people without a matching role; there is no cursor or exhaustive-search guarantee." } }, "required": [ "roles" ], "additionalProperties": false, "examples": [ { "roles": [ { "person_key": "registry_person_kari", "full_name": "Kari Nordmann", "birth_date": "1980-04-12", "roles": [ { "org_number": "999999999", "company_name": "Northstar Consulting AS", "role_group": "STYR", "role_code": "LEDE", "resigned": false } ] } ] } ] } ``` --- # Get deal Read a deal by ID. Returns item: null when no visible record matches. POST https://api.brigg.app/v1/operations/customers.GetDeal ## Access & visibility Allow `customers.GetDeal` on your API key. Resource read permissions: `core:Deal`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:Deal` record. Find it with [customers.ListDeals](/developers/reference/customers/ListDeals). Use the record's top-level `id`, not a business field or account ID. | ## Response Returns **200 OK** with a JSON body. `item: null` means there is no matching record visible to this caller. It does not reveal whether an inaccessible record exists. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. The public schema lists accepted stage IDs. Labels are presentation text; use the stable stage ID in calls. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [DealRecord](#dealrecord-response-item) or null | Yes | null when no such record | ### DealRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Deal record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Deal](#deal-response-item-data) | Yes | The record's fields. | ### Deal · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string | Yes | Name of the sales opportunity. | | `stage` | string | Yes | A stage id from the org's own sales pipeline, in funnel order: lead = Lead, qualified = Qualified, proposal = Proposal, negotiation = Negotiation, won = Won (won), lost = Lost (lost). The list is the org's to change — the pipeline is the `core:SalesPipeline` entry (edit its `stages` to add, rename, reorder or re-weight a stage; the ids here follow). Allowed: `"lead"`, `"qualified"`, `"proposal"`, `"negotiation"`, `"won"`, `"lost"`. | | `amount_ore` | integer | No | Value of the opportunity in Norwegian øre. 1000000 is NOK 10,000. Deals are NOK-only; do not supply another currency. | | `product_lines` | array of [object](#response-item-data-product-lines) | No | Products or services proposed in this deal, with quantities, prices and billing frequency. | | `company_ref` | string | No | ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name. | | `contact_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `owner_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `expected_close_date` | string | No | Expected date the opportunity will be won or lost, in YYYY-MM-DD format. | | `description` | string | No | Business context for the sales opportunity. | | `lost_reason` | string | No | Reason recorded when the opportunity is lost. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | ### response.item.data.product_lines[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `product_ref` | string | No | Product record ID. | | `name` | string | Yes | Display name. | | `description` | string | No | Descriptive text. | | `quantity` | number | No | Number of units. May be fractional when the product allows it. Minimum: 0. | | `unit` | string | No | Unit used for the quantity, such as hours or items. | | `unit_price_ore` | integer | No | Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only. | | `agreed_at` | number | No | Time the commercial terms were agreed, in Unix milliseconds. | | `agreed_deal_ref` | string | No | Deal record ID. | | `revenue_type` | string | No | Whether this amount is charged once or repeats monthly, quarterly or annually. Allowed: `"one_time"`, `"monthly"`, `"quarterly"`, `"annual"`. | | `start_date` | string | No | ISO date (YYYY-MM-DD) | | `end_date` | string | No | ISO date (YYYY-MM-DD) | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [List deals](/developers/reference/customers/ListDeals) - [Create deal](/developers/reference/customers/CreateDeal) - [Upsert deal](/developers/reference/customers/UpsertDeal) - [Update deal](/developers/reference/customers/UpdateDeal) - [Delete deal](/developers/reference/customers/DeleteDeal) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.GetDeal' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "e_deal_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.GetDeal", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "id": "e_deal_example" }), }); 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 payload = { "id": "e_deal_example" } request = Request( "https://api.brigg.app/v1/operations/customers.GetDeal", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "item": { "id": "e_deal_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "title": "Customer onboarding project", "stage": "proposal", "amount_ore": 1000000, "company_ref": "e_company_example", "contact_ref": "e_person_example", "expected_close_date": "2026-11-30" } } } ``` ### No visible record A missing or inaccessible record returns item: null. Do not treat this as proof that a record exists for another member. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.GetDeal' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "e_deal_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.GetDeal", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "id": "e_deal_example" }), }); 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 payload = { "id": "e_deal_example" } request = Request( "https://api.brigg.app/v1/operations/customers.GetDeal", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "item": null } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:Deal` record. Find it with [customers.ListDeals](/developers/reference/customers/ListDeals). Use the record's top-level `id`, not a business field or account ID." } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_deal_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": [ "object", "null" ], "properties": { "id": { "type": "string", "description": "Stable core:Deal record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "title": { "type": "string", "description": "Name of the sales opportunity." }, "stage": { "type": "string", "enum": [ "lead", "qualified", "proposal", "negotiation", "won", "lost" ], "description": "A stage id from the org's own sales pipeline, in funnel order: lead = Lead, qualified = Qualified, proposal = Proposal, negotiation = Negotiation, won = Won (won), lost = Lost (lost). The list is the org's to change — the pipeline is the `core:SalesPipeline` entry (edit its `stages` to add, rename, reorder or re-weight a stage; the ids here follow)." }, "amount_ore": { "type": "integer", "description": "Value of the opportunity in Norwegian øre. 1000000 is NOK 10,000. Deals are NOK-only; do not supply another currency." }, "product_lines": { "type": "array", "items": { "type": "object", "properties": { "product_ref": { "type": "string", "description": "Product record ID." }, "name": { "type": "string", "description": "Display name." }, "description": { "type": "string", "description": "Descriptive text." }, "quantity": { "type": "number", "minimum": 0, "description": "Number of units. May be fractional when the product allows it." }, "unit": { "type": "string", "description": "Unit used for the quantity, such as hours or items." }, "unit_price_ore": { "type": "integer", "description": "Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only." }, "agreed_at": { "type": "number", "description": "Time the commercial terms were agreed, in Unix milliseconds." }, "agreed_deal_ref": { "type": "string", "description": "Deal record ID." }, "revenue_type": { "type": "string", "enum": [ "one_time", "monthly", "quarterly", "annual" ], "description": "Whether this amount is charged once or repeats monthly, quarterly or annually." }, "start_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" }, "end_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" } }, "required": [ "name" ], "additionalProperties": false }, "description": "Products or services proposed in this deal, with quantities, prices and billing frequency." }, "company_ref": { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." }, "contact_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "owner_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "expected_close_date": { "type": "string", "description": "Expected date the opportunity will be won or lost, in YYYY-MM-DD format." }, "description": { "type": "string", "description": "Business context for the sales opportunity." }, "lost_reason": { "type": "string", "description": "Reason recorded when the opportunity is lost." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." } }, "required": [ "title", "stage" ], "additionalProperties": false, "description": "The record's fields.", "title": "Deal" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "null when no such record", "title": "DealRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_deal_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "title": "Customer onboarding project", "stage": "proposal", "amount_ore": 1000000, "company_ref": "e_company_example", "contact_ref": "e_person_example", "expected_close_date": "2026-11-30" } } } ] } ``` --- # List deals List deals visible to the credential, with filtering, sorting and cursor pagination. POST https://api.brigg.app/v1/operations/customers.ListDeals ## Access & visibility Allow `customers.ListDeals` on your API key. Resource read permissions: `core:Deal`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `filters` | array of [object](#request-filters) | No | Conditions the row must ALL satisfy. | | `sort` | [object](#request-sort) | No | Sort order for the results. Defaults to updated_at descending, with id as a tie-breaker. | | `limit` | integer | No | Maximum number of results to return in this page. Continue with next_cursor when returned. Default: `100`. Minimum: 1. | | `cursor` | string | No | The `next_cursor` of the previous page. | ### request.filters[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | `data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private. Allowed: `"id"`, `"created_at"`, `"updated_at"`, `"created_by"`, `"private"`, `"data.title"`, `"data.stage"`, `"data.amount_ore"`, `"data.product_lines"`, `"data.company_ref"`, `"data.contact_ref"`, `"data.owner_ref"`, `"data.expected_close_date"`, `"data.description"`, `"data.lost_reason"`, `"data.tags"`. | | `op` | string | Yes | Comparison operator. Use in with an array, or omit value for is_empty and is_not_empty. Allowed: `"eq"`, `"neq"`, `"contains"`, `"starts_with"`, `"gt"`, `"gte"`, `"lt"`, `"lte"`, `"in"`, `"has"`, `"is_empty"`, `"is_not_empty"`. | | `value` | JSON value | No | The comparison value; an array for `in`; omitted for is_empty / is_not_empty. | ### request.sort | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | `data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private. Allowed: `"id"`, `"created_at"`, `"updated_at"`, `"created_by"`, `"private"`, `"data.title"`, `"data.stage"`, `"data.amount_ore"`, `"data.product_lines"`, `"data.company_ref"`, `"data.contact_ref"`, `"data.owner_ref"`, `"data.expected_close_date"`, `"data.description"`, `"data.lost_reason"`, `"data.tags"`. | | `direction` | string | No | Sort direction: asc for ascending or desc for descending. Allowed: `"asc"`, `"desc"`. | ## Filtering and sorting All conditions are combined with **AND**. Address business fields as `data.`, and record metadata as `id`, `created_at`, `updated_at`, `created_by` or `private`. A field path names one field; it does not traverse nested objects. | Operator | Meaning | Value | | --- | --- | --- | | `eq` | Equal to a scalar | String, number, boolean or null | | `neq` | Not equal; missing values also match | String, number, boolean or null | | `contains` | Case-insensitive text contains | String; % and _ are literal characters | | `starts_with` | Case-insensitive text prefix | String | | `gt`, `gte` | Greater than / at least | Number or string appropriate to the field | | `lt`, `lte` | Less than / at most | Number or string appropriate to the field | | `in` | Equal to any supplied scalar | Nonempty array of strings, numbers, booleans or null | | `has` | Array contains a string | One string; does not match properties inside array objects | | `is_empty` | Missing, null, empty string or empty array | Omit value | | `is_not_empty` | Has a nonempty value | Omit value | Match the stored field's type. Numeric business timestamps take Unix milliseconds; date-only business fields take `YYYY-MM-DD`. The record metadata fields `created_at` and `updated_at` also accept ISO timestamps for ordered comparisons. Sorting defaults to `updated_at` descending. If you supply `sort.field` without `sort.direction`, direction is `desc`. The record ID breaks ties; missing values sort last. ## Response Returns **200 OK** with a JSON body. An empty `items` array means this page contains no matching visible results. Follow `next_cursor` when present. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. The public schema lists accepted stage IDs. Labels are presentation text; use the stable stage ID in calls. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [DealRecord](#dealrecord-response-items) | Yes | Records visible under the credential's grants and the selected data scope, matching the requested filters. Pass next_cursor as cursor to continue when a next cursor is returned. | | `next_cursor` | string | No | Pass this value as cursor to continue with the same filters, sort and credential. Omitted when there are no more results. | ### DealRecord · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Deal record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Deal](#deal-response-items-data) | Yes | The record's fields. | ### Deal · response.items[].data | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string | Yes | Name of the sales opportunity. | | `stage` | string | Yes | A stage id from the org's own sales pipeline, in funnel order: lead = Lead, qualified = Qualified, proposal = Proposal, negotiation = Negotiation, won = Won (won), lost = Lost (lost). The list is the org's to change — the pipeline is the `core:SalesPipeline` entry (edit its `stages` to add, rename, reorder or re-weight a stage; the ids here follow). Allowed: `"lead"`, `"qualified"`, `"proposal"`, `"negotiation"`, `"won"`, `"lost"`. | | `amount_ore` | integer | No | Value of the opportunity in Norwegian øre. 1000000 is NOK 10,000. Deals are NOK-only; do not supply another currency. | | `product_lines` | array of [object](#response-items-data-product-lines) | No | Products or services proposed in this deal, with quantities, prices and billing frequency. | | `company_ref` | string | No | ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name. | | `contact_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `owner_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `expected_close_date` | string | No | Expected date the opportunity will be won or lost, in YYYY-MM-DD format. | | `description` | string | No | Business context for the sales opportunity. | | `lost_reason` | string | No | Reason recorded when the opportunity is lost. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | ### response.items[].data.product_lines[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `product_ref` | string | No | Product record ID. | | `name` | string | Yes | Display name. | | `description` | string | No | Descriptive text. | | `quantity` | number | No | Number of units. May be fractional when the product allows it. Minimum: 0. | | `unit` | string | No | Unit used for the quantity, such as hours or items. | | `unit_price_ore` | integer | No | Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only. | | `agreed_at` | number | No | Time the commercial terms were agreed, in Unix milliseconds. | | `agreed_deal_ref` | string | No | Deal record ID. | | `revenue_type` | string | No | Whether this amount is charged once or repeats monthly, quarterly or annually. Allowed: `"one_time"`, `"monthly"`, `"quarterly"`, `"annual"`. | | `start_date` | string | No | ISO date (YYYY-MM-DD) | | `end_date` | string | No | ISO date (YYYY-MM-DD) | ## Pagination Pass `next_cursor` from the response as `cursor` on the next request. Keep the same filters, sort and acting identity. Stop when `next_cursor` is absent; do not infer completion from the number of items. The default page size is **100**; `limit` must be a positive integer. **Pagination is a live view, not a snapshot.** Changes between pages can move records across page boundaries. Upsert by record ID rather than appending blindly. For recurring synchronization, use an overlapping update window and deduplicate records. Periodically reconcile IDs to detect deletions. [Resource webhooks](/developers/webhooks) can supplement synchronization for eligible workspace-shared records only: they do not export private or project-scoped records. Personal data still needs polling and reconciliation. ```typescript const query = { "limit": 10 }; let cursor; do { const response = await fetch("https://api.brigg.app/v1/operations/customers.ListDeals", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ ...query, ...(cursor ? { cursor } : {}) }), }); const page = await response.json(); if (!response.ok) throw new Error(`${response.status}: ${page.message}`); for (const item of page.items) { console.log(item); // Process or upsert each result. } cursor = page.next_cursor; } while (cursor); ``` ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | | 400 | `cursor_invalid` | Restart pagination with no cursor. | | 400 | `cursor_mismatch` | Use the cursor with the original filters, sort order and credential. | ## Next steps - [Get deal](/developers/reference/customers/GetDeal) - [Create deal](/developers/reference/customers/CreateDeal) - [Upsert deal](/developers/reference/customers/UpsertDeal) - [Update deal](/developers/reference/customers/UpdateDeal) - [Delete deal](/developers/reference/customers/DeleteDeal) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### First page Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.ListDeals' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "limit": 10 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.ListDeals", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "limit": 10 }), }); 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 payload = { "limit": 10 } request = Request( "https://api.brigg.app/v1/operations/customers.ListDeals", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_deal_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "title": "Customer onboarding project", "stage": "proposal", "amount_ore": 1000000, "company_ref": "e_company_example", "contact_ref": "e_person_example", "expected_close_date": "2026-11-30" } } ] } ``` ### Open proposals Use the stored stage value, not a translated label. Add a company_ref filter to restrict the pipeline to one customer. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.ListDeals' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "limit": 50, "filters": [ { "field": "data.stage", "op": "eq", "value": "proposal" } ] }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.ListDeals", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "limit": 50, "filters": [ { "field": "data.stage", "op": "eq", "value": "proposal" } ] }), }); 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 payload = { "limit": 50, "filters": [ { "field": "data.stage", "op": "eq", "value": "proposal" } ] } request = Request( "https://api.brigg.app/v1/operations/customers.ListDeals", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_deal_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "title": "Customer onboarding project", "stage": "proposal", "amount_ore": 1000000, "company_ref": "e_company_example", "contact_ref": "e_person_example", "expected_close_date": "2026-11-30" } } ] } ``` ### Records updated since a checkpoint 6 October 2026 at 00:00 UTC. Use an overlap window and upsert by ID when synchronizing. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.ListDeals' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.ListDeals", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 }), }); 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 payload = { "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 } request = Request( "https://api.brigg.app/v1/operations/customers.ListDeals", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_deal_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "title": "Customer onboarding project", "stage": "proposal", "amount_ore": 1000000, "company_ref": "e_company_example", "contact_ref": "e_person_example", "expected_close_date": "2026-11-30" } } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "filters": { "type": "array", "items": { "type": "object", "properties": { "field": { "type": "string", "description": "`data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private.", "enum": [ "id", "created_at", "updated_at", "created_by", "private", "data.title", "data.stage", "data.amount_ore", "data.product_lines", "data.company_ref", "data.contact_ref", "data.owner_ref", "data.expected_close_date", "data.description", "data.lost_reason", "data.tags" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "contains", "starts_with", "gt", "gte", "lt", "lte", "in", "has", "is_empty", "is_not_empty" ], "description": "Comparison operator. Use in with an array, or omit value for is_empty and is_not_empty." }, "value": { "description": "The comparison value; an array for `in`; omitted for is_empty / is_not_empty." } }, "required": [ "field", "op" ], "additionalProperties": false }, "description": "Conditions the row must ALL satisfy." }, "sort": { "type": "object", "properties": { "field": { "type": "string", "description": "`data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private.", "enum": [ "id", "created_at", "updated_at", "created_by", "private", "data.title", "data.stage", "data.amount_ore", "data.product_lines", "data.company_ref", "data.contact_ref", "data.owner_ref", "data.expected_close_date", "data.description", "data.lost_reason", "data.tags" ] }, "direction": { "type": "string", "enum": [ "asc", "desc" ], "description": "Sort direction: asc for ascending or desc for descending." } }, "required": [ "field" ], "additionalProperties": false, "description": "Sort order for the results. Defaults to updated_at descending, with id as a tie-breaker." }, "limit": { "type": "integer", "minimum": 1, "default": 100, "description": "Maximum number of results to return in this page. Continue with next_cursor when returned." }, "cursor": { "type": "string", "description": "The `next_cursor` of the previous page." } }, "additionalProperties": false, "examples": [ { "limit": 10 } ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:Deal record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "title": { "type": "string", "description": "Name of the sales opportunity." }, "stage": { "type": "string", "enum": [ "lead", "qualified", "proposal", "negotiation", "won", "lost" ], "description": "A stage id from the org's own sales pipeline, in funnel order: lead = Lead, qualified = Qualified, proposal = Proposal, negotiation = Negotiation, won = Won (won), lost = Lost (lost). The list is the org's to change — the pipeline is the `core:SalesPipeline` entry (edit its `stages` to add, rename, reorder or re-weight a stage; the ids here follow)." }, "amount_ore": { "type": "integer", "description": "Value of the opportunity in Norwegian øre. 1000000 is NOK 10,000. Deals are NOK-only; do not supply another currency." }, "product_lines": { "type": "array", "items": { "type": "object", "properties": { "product_ref": { "type": "string", "description": "Product record ID." }, "name": { "type": "string", "description": "Display name." }, "description": { "type": "string", "description": "Descriptive text." }, "quantity": { "type": "number", "minimum": 0, "description": "Number of units. May be fractional when the product allows it." }, "unit": { "type": "string", "description": "Unit used for the quantity, such as hours or items." }, "unit_price_ore": { "type": "integer", "description": "Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only." }, "agreed_at": { "type": "number", "description": "Time the commercial terms were agreed, in Unix milliseconds." }, "agreed_deal_ref": { "type": "string", "description": "Deal record ID." }, "revenue_type": { "type": "string", "enum": [ "one_time", "monthly", "quarterly", "annual" ], "description": "Whether this amount is charged once or repeats monthly, quarterly or annually." }, "start_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" }, "end_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" } }, "required": [ "name" ], "additionalProperties": false }, "description": "Products or services proposed in this deal, with quantities, prices and billing frequency." }, "company_ref": { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." }, "contact_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "owner_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "expected_close_date": { "type": "string", "description": "Expected date the opportunity will be won or lost, in YYYY-MM-DD format." }, "description": { "type": "string", "description": "Business context for the sales opportunity." }, "lost_reason": { "type": "string", "description": "Reason recorded when the opportunity is lost." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." } }, "required": [ "title", "stage" ], "additionalProperties": false, "description": "The record's fields.", "title": "Deal" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "title": "DealRecord" }, "description": "Records visible under the credential's grants and the selected data scope, matching the requested filters. Pass next_cursor as cursor to continue when a next cursor is returned." }, "next_cursor": { "type": "string", "description": "Pass this value as cursor to continue with the same filters, sort and credential. Omitted when there are no more results." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "id": "e_deal_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "title": "Customer onboarding project", "stage": "proposal", "amount_ore": 1000000, "company_ref": "e_company_example", "contact_ref": "e_person_example", "expected_close_date": "2026-11-30" } } ] } ] } ``` --- # Create deal Create a deal and return the saved record. POST https://api.brigg.app/v1/operations/customers.CreateDeal ## Access & visibility Allow `customers.CreateDeal` on your API key. Resource read permissions: `core:Deal`. Resource write permissions: `core:Deal`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `data` | [Deal](#deal-request-data) | Yes | The record's fields. | | `private` | boolean | No | Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance. | ### Deal · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string | Yes | Name of the sales opportunity. | | `stage` | string | Yes | A stage id from the org's own sales pipeline, in funnel order: lead = Lead, qualified = Qualified, proposal = Proposal, negotiation = Negotiation, won = Won (won), lost = Lost (lost). The list is the org's to change — the pipeline is the `core:SalesPipeline` entry (edit its `stages` to add, rename, reorder or re-weight a stage; the ids here follow). Allowed: `"lead"`, `"qualified"`, `"proposal"`, `"negotiation"`, `"won"`, `"lost"`. | | `amount_ore` | integer | No | Value of the opportunity in Norwegian øre. 1000000 is NOK 10,000. Deals are NOK-only; do not supply another currency. | | `product_lines` | array of [object](#request-data-product-lines) | No | Products or services proposed in this deal, with quantities, prices and billing frequency. | | `company_ref` | string | No | ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name. | | `contact_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `owner_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `expected_close_date` | string | No | Expected date the opportunity will be won or lost, in YYYY-MM-DD format. | | `description` | string | No | Business context for the sales opportunity. | | `lost_reason` | string | No | Reason recorded when the opportunity is lost. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | ### request.data.product_lines[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `product_ref` | string | No | Product record ID. | | `name` | string | Yes | Display name. | | `description` | string | No | Descriptive text. | | `quantity` | number | No | Number of units. May be fractional when the product allows it. Minimum: 0. | | `unit` | string | No | Unit used for the quantity, such as hours or items. | | `unit_price_ore` | integer | No | Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only. | | `agreed_at` | number | No | Time the commercial terms were agreed, in Unix milliseconds. | | `agreed_deal_ref` | string | No | Deal record ID. | | `revenue_type` | string | No | Whether this amount is charged once or repeats monthly, quarterly or annually. Allowed: `"one_time"`, `"monthly"`, `"quarterly"`, `"annual"`. | | `start_date` | string | No | ISO date (YYYY-MM-DD) | | `end_date` | string | No | ISO date (YYYY-MM-DD) | ## Choose ownership deliberately Omitting `private`, or setting it to false, creates a workspace-shared record. Set `private: true` to create a record owned by the approved acting member. Private records require member delegation; a workspace-only credential cannot own a personal record. The credential’s exact resource grants authorize the write; private ownership and project membership remain enforced. A create is a new record, not an upsert. Reuse the same idempotency key only for retries of that logical creation. For recurring synchronization, use the resource’s upsert operation when available: it matches a permanent external reference. Otherwise keep the returned record ID and use the corresponding update operation for subsequent changes. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. The public schema lists accepted stage IDs. Labels are presentation text; use the stable stage ID in calls. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [DealRecord](#dealrecord-response-item) | Yes | The requested record, including its metadata and data fields. | ### DealRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Deal record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Deal](#deal-response-item-data) | Yes | The record's fields. | ### Deal · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string | Yes | Name of the sales opportunity. | | `stage` | string | Yes | A stage id from the org's own sales pipeline, in funnel order: lead = Lead, qualified = Qualified, proposal = Proposal, negotiation = Negotiation, won = Won (won), lost = Lost (lost). The list is the org's to change — the pipeline is the `core:SalesPipeline` entry (edit its `stages` to add, rename, reorder or re-weight a stage; the ids here follow). Allowed: `"lead"`, `"qualified"`, `"proposal"`, `"negotiation"`, `"won"`, `"lost"`. | | `amount_ore` | integer | No | Value of the opportunity in Norwegian øre. 1000000 is NOK 10,000. Deals are NOK-only; do not supply another currency. | | `product_lines` | array of [object](#response-item-data-product-lines) | No | Products or services proposed in this deal, with quantities, prices and billing frequency. | | `company_ref` | string | No | ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name. | | `contact_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `owner_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `expected_close_date` | string | No | Expected date the opportunity will be won or lost, in YYYY-MM-DD format. | | `description` | string | No | Business context for the sales opportunity. | | `lost_reason` | string | No | Reason recorded when the opportunity is lost. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | ### response.item.data.product_lines[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `product_ref` | string | No | Product record ID. | | `name` | string | Yes | Display name. | | `description` | string | No | Descriptive text. | | `quantity` | number | No | Number of units. May be fractional when the product allows it. Minimum: 0. | | `unit` | string | No | Unit used for the quantity, such as hours or items. | | `unit_price_ore` | integer | No | Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only. | | `agreed_at` | number | No | Time the commercial terms were agreed, in Unix milliseconds. | | `agreed_deal_ref` | string | No | Deal record ID. | | `revenue_type` | string | No | Whether this amount is charged once or repeats monthly, quarterly or annually. Allowed: `"one_time"`, `"monthly"`, `"quarterly"`, `"annual"`. | | `start_date` | string | No | ISO date (YYYY-MM-DD) | | `end_date` | string | No | ISO date (YYYY-MM-DD) | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List deals](/developers/reference/customers/ListDeals) - [Get deal](/developers/reference/customers/GetDeal) - [Upsert deal](/developers/reference/customers/UpsertDeal) - [Update deal](/developers/reference/customers/UpdateDeal) - [Delete deal](/developers/reference/customers/DeleteDeal) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.CreateDeal' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "data": { "title": "Customer onboarding project", "stage": "proposal", "amount_ore": 1000000, "company_ref": "e_company_example", "contact_ref": "e_person_example", "expected_close_date": "2026-11-30" } }' ``` #### TypeScript ```typescript 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/customers.CreateDeal", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "data": { "title": "Customer onboarding project", "stage": "proposal", "amount_ore": 1000000, "company_ref": "e_company_example", "contact_ref": "e_person_example", "expected_close_date": "2026-11-30" } }), }); 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 = { "data": { "title": "Customer onboarding project", "stage": "proposal", "amount_ore": 1000000, "company_ref": "e_company_example", "contact_ref": "e_person_example", "expected_close_date": "2026-11-30" } } request = Request( "https://api.brigg.app/v1/operations/customers.CreateDeal", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_deal_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "title": "Customer onboarding project", "stage": "proposal", "amount_ore": 1000000, "company_ref": "e_company_example", "contact_ref": "e_person_example", "expected_close_date": "2026-11-30" } } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "data": { "type": "object", "properties": { "title": { "type": "string", "description": "Name of the sales opportunity." }, "stage": { "type": "string", "enum": [ "lead", "qualified", "proposal", "negotiation", "won", "lost" ], "description": "A stage id from the org's own sales pipeline, in funnel order: lead = Lead, qualified = Qualified, proposal = Proposal, negotiation = Negotiation, won = Won (won), lost = Lost (lost). The list is the org's to change — the pipeline is the `core:SalesPipeline` entry (edit its `stages` to add, rename, reorder or re-weight a stage; the ids here follow)." }, "amount_ore": { "type": "integer", "description": "Value of the opportunity in Norwegian øre. 1000000 is NOK 10,000. Deals are NOK-only; do not supply another currency." }, "product_lines": { "type": "array", "items": { "type": "object", "properties": { "product_ref": { "type": "string", "description": "Product record ID." }, "name": { "type": "string", "description": "Display name." }, "description": { "type": "string", "description": "Descriptive text." }, "quantity": { "type": "number", "minimum": 0, "description": "Number of units. May be fractional when the product allows it." }, "unit": { "type": "string", "description": "Unit used for the quantity, such as hours or items." }, "unit_price_ore": { "type": "integer", "description": "Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only." }, "agreed_at": { "type": "number", "description": "Time the commercial terms were agreed, in Unix milliseconds." }, "agreed_deal_ref": { "type": "string", "description": "Deal record ID." }, "revenue_type": { "type": "string", "enum": [ "one_time", "monthly", "quarterly", "annual" ], "description": "Whether this amount is charged once or repeats monthly, quarterly or annually." }, "start_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" }, "end_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" } }, "required": [ "name" ], "additionalProperties": false }, "description": "Products or services proposed in this deal, with quantities, prices and billing frequency." }, "company_ref": { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." }, "contact_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "owner_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "expected_close_date": { "type": "string", "description": "Expected date the opportunity will be won or lost, in YYYY-MM-DD format." }, "description": { "type": "string", "description": "Business context for the sales opportunity." }, "lost_reason": { "type": "string", "description": "Reason recorded when the opportunity is lost." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." } }, "required": [ "title", "stage" ], "additionalProperties": false, "description": "The record's fields.", "title": "Deal" }, "private": { "type": "boolean", "description": "Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance." } }, "required": [ "data" ], "additionalProperties": false, "examples": [ { "data": { "title": "Customer onboarding project", "stage": "proposal", "amount_ore": 1000000, "company_ref": "e_company_example", "contact_ref": "e_person_example", "expected_close_date": "2026-11-30" } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:Deal record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "title": { "type": "string", "description": "Name of the sales opportunity." }, "stage": { "type": "string", "enum": [ "lead", "qualified", "proposal", "negotiation", "won", "lost" ], "description": "A stage id from the org's own sales pipeline, in funnel order: lead = Lead, qualified = Qualified, proposal = Proposal, negotiation = Negotiation, won = Won (won), lost = Lost (lost). The list is the org's to change — the pipeline is the `core:SalesPipeline` entry (edit its `stages` to add, rename, reorder or re-weight a stage; the ids here follow)." }, "amount_ore": { "type": "integer", "description": "Value of the opportunity in Norwegian øre. 1000000 is NOK 10,000. Deals are NOK-only; do not supply another currency." }, "product_lines": { "type": "array", "items": { "type": "object", "properties": { "product_ref": { "type": "string", "description": "Product record ID." }, "name": { "type": "string", "description": "Display name." }, "description": { "type": "string", "description": "Descriptive text." }, "quantity": { "type": "number", "minimum": 0, "description": "Number of units. May be fractional when the product allows it." }, "unit": { "type": "string", "description": "Unit used for the quantity, such as hours or items." }, "unit_price_ore": { "type": "integer", "description": "Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only." }, "agreed_at": { "type": "number", "description": "Time the commercial terms were agreed, in Unix milliseconds." }, "agreed_deal_ref": { "type": "string", "description": "Deal record ID." }, "revenue_type": { "type": "string", "enum": [ "one_time", "monthly", "quarterly", "annual" ], "description": "Whether this amount is charged once or repeats monthly, quarterly or annually." }, "start_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" }, "end_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" } }, "required": [ "name" ], "additionalProperties": false }, "description": "Products or services proposed in this deal, with quantities, prices and billing frequency." }, "company_ref": { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." }, "contact_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "owner_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "expected_close_date": { "type": "string", "description": "Expected date the opportunity will be won or lost, in YYYY-MM-DD format." }, "description": { "type": "string", "description": "Business context for the sales opportunity." }, "lost_reason": { "type": "string", "description": "Reason recorded when the opportunity is lost." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." } }, "required": [ "title", "stage" ], "additionalProperties": false, "description": "The record's fields.", "title": "Deal" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "DealRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_deal_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "title": "Customer onboarding project", "stage": "proposal", "amount_ore": 1000000, "company_ref": "e_company_example", "contact_ref": "e_person_example", "expected_close_date": "2026-11-30" } } } ] } ``` --- # Delete deal Delete a deal by ID. Repeating a deletion returns already_deleted. POST https://api.brigg.app/v1/operations/customers.DeleteDeal ## Access & visibility Allow `customers.DeleteDeal` on your API key. Resource read permissions: `core:Deal`. Resource write permissions: `core:Deal`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:Deal` record. Find it with [customers.ListDeals](/developers/reference/customers/ListDeals). Use the record's top-level `id`, not a business field or account ID. | | `expected` | [object](#request-expected) | No | Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {"$absent":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource. | ### request.expected | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string or [object](#request-expected-title) | No | Commit only if the previous title value matches; use $absent to require that this field is missing. | | `stage` | string or [object](#request-expected-stage) | No | Commit only if the previous stage value matches; use $absent to require that this field is missing. | | `amount_ore` | integer or [object](#request-expected-amount-ore) | No | Commit only if the previous amount_ore value matches; use $absent to require that this field is missing. | | `product_lines` | array of [object](#request-expected-product-lines) or [object](#request-expected-product-lines) | No | Commit only if the previous product_lines value matches; use $absent to require that this field is missing. | | `company_ref` | string or [object](#request-expected-company-ref) | No | Commit only if the previous company_ref value matches; use $absent to require that this field is missing. | | `contact_ref` | string or [object](#request-expected-contact-ref) | No | Commit only if the previous contact_ref value matches; use $absent to require that this field is missing. | | `owner_ref` | string or [object](#request-expected-owner-ref) | No | Commit only if the previous owner_ref value matches; use $absent to require that this field is missing. | | `expected_close_date` | string or [object](#request-expected-expected-close-date) | No | Commit only if the previous expected_close_date value matches; use $absent to require that this field is missing. | | `description` | string or [object](#request-expected-description) | No | Commit only if the previous description value matches; use $absent to require that this field is missing. | | `lost_reason` | string or [object](#request-expected-lost-reason) | No | Commit only if the previous lost_reason value matches; use $absent to require that this field is missing. | | `tags` | array of string or [object](#request-expected-tags) | No | Commit only if the previous tags value matches; use $absent to require that this field is missing. | ### request.expected.title | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.stage | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.amount_ore | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.product_lines | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.product_lines[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `product_ref` | string | No | Product record ID. | | `name` | string | Yes | Display name. | | `description` | string | No | Descriptive text. | | `quantity` | number | No | Number of units. May be fractional when the product allows it. Minimum: 0. | | `unit` | string | No | Unit used for the quantity, such as hours or items. | | `unit_price_ore` | integer | No | Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only. | | `agreed_at` | number | No | Time the commercial terms were agreed, in Unix milliseconds. | | `agreed_deal_ref` | string | No | Deal record ID. | | `revenue_type` | string | No | Whether this amount is charged once or repeats monthly, quarterly or annually. Allowed: `"one_time"`, `"monthly"`, `"quarterly"`, `"annual"`. | | `start_date` | string | No | ISO date (YYYY-MM-DD) | | `end_date` | string | No | ISO date (YYYY-MM-DD) | ### request.expected.company_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.contact_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.owner_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.expected_close_date | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.description | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.lost_reason | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.tags | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ## Deletion and retries A successful response reports whether this call removed the record or it was already absent. Check `cascaded` for dependent record IDs returned by the operation. Retrying the same action uses the original idempotency key. A successful deletion is not an archive you can restore through this operation. To avoid deleting a record someone has changed, read it first and put the relevant prior business values in `expected`. Keys are relative to `data`, not prefixed with `data.`. Use {"$absent": true} to require a missing field. A mismatch returns 409 conflict; read again and decide whether deletion is still appropriate. A revised action needs a new idempotency key. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `deleted` | string | Yes | deleted when this request removed the record; already_deleted when it was already absent. Allowed: `"deleted"`, `"already_deleted"`. | | `cascaded` | array of string | No | IDs of dependent records deleted with this 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `conflict` | A supplied expected value no longer matches. Read the record again before deciding whether to retry. | ## Next steps - [List deals](/developers/reference/customers/ListDeals) - [Get deal](/developers/reference/customers/GetDeal) - [Create deal](/developers/reference/customers/CreateDeal) - [Upsert deal](/developers/reference/customers/UpsertDeal) - [Update deal](/developers/reference/customers/UpdateDeal) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.DeleteDeal' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_deal_example" }' ``` #### TypeScript ```typescript 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/customers.DeleteDeal", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_deal_example" }), }); 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_deal_example" } request = Request( "https://api.brigg.app/v1/operations/customers.DeleteDeal", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "deleted": "deleted" } ``` ### Delete only if unchanged Use a value you actually read. A concurrent change refuses the write with 409 conflict. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.DeleteDeal' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_deal_example", "expected": { "title": "Customer onboarding project" } }' ``` #### TypeScript ```typescript 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/customers.DeleteDeal", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_deal_example", "expected": { "title": "Customer onboarding project" } }), }); 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_deal_example", "expected": { "title": "Customer onboarding project" } } request = Request( "https://api.brigg.app/v1/operations/customers.DeleteDeal", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "deleted": "deleted" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:Deal` record. Find it with [customers.ListDeals](/developers/reference/customers/ListDeals). Use the record's top-level `id`, not a business field or account ID." }, "expected": { "type": "object", "description": "Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {\"$absent\":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource.", "additionalProperties": false, "properties": { "title": { "description": "Commit only if the previous title value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Name of the sales opportunity." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "stage": { "description": "Commit only if the previous stage value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "enum": [ "lead", "qualified", "proposal", "negotiation", "won", "lost" ], "description": "A stage id from the org's own sales pipeline, in funnel order: lead = Lead, qualified = Qualified, proposal = Proposal, negotiation = Negotiation, won = Won (won), lost = Lost (lost). The list is the org's to change — the pipeline is the `core:SalesPipeline` entry (edit its `stages` to add, rename, reorder or re-weight a stage; the ids here follow)." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "amount_ore": { "description": "Commit only if the previous amount_ore value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "integer", "description": "Value of the opportunity in Norwegian øre. 1000000 is NOK 10,000. Deals are NOK-only; do not supply another currency." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "product_lines": { "description": "Commit only if the previous product_lines value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "type": "object", "properties": { "product_ref": { "type": "string", "description": "Product record ID." }, "name": { "type": "string", "description": "Display name." }, "description": { "type": "string", "description": "Descriptive text." }, "quantity": { "type": "number", "minimum": 0, "description": "Number of units. May be fractional when the product allows it." }, "unit": { "type": "string", "description": "Unit used for the quantity, such as hours or items." }, "unit_price_ore": { "type": "integer", "description": "Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only." }, "agreed_at": { "type": "number", "description": "Time the commercial terms were agreed, in Unix milliseconds." }, "agreed_deal_ref": { "type": "string", "description": "Deal record ID." }, "revenue_type": { "type": "string", "enum": [ "one_time", "monthly", "quarterly", "annual" ], "description": "Whether this amount is charged once or repeats monthly, quarterly or annually." }, "start_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" }, "end_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" } }, "required": [ "name" ], "additionalProperties": false }, "description": "Products or services proposed in this deal, with quantities, prices and billing frequency." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "company_ref": { "description": "Commit only if the previous company_ref value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "contact_ref": { "description": "Commit only if the previous contact_ref value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "owner_ref": { "description": "Commit only if the previous owner_ref value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "expected_close_date": { "description": "Commit only if the previous expected_close_date value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Expected date the opportunity will be won or lost, in YYYY-MM-DD format." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "description": { "description": "Commit only if the previous description value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Business context for the sales opportunity." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "lost_reason": { "description": "Commit only if the previous lost_reason value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Reason recorded when the opportunity is lost." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "tags": { "description": "Commit only if the previous tags value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] } } } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_deal_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "deleted": { "type": "string", "enum": [ "deleted", "already_deleted" ], "description": "deleted when this request removed the record; already_deleted when it was already absent." }, "cascaded": { "type": "array", "items": { "type": "string" }, "description": "IDs of dependent records deleted with this record." } }, "required": [ "deleted" ], "additionalProperties": false, "examples": [ { "deleted": "deleted" } ] } ``` --- # Update deal Update a deal by ID. Omitted fields stay unchanged; use unset to remove fields and expected to prevent overwriting a concurrent change. POST https://api.brigg.app/v1/operations/customers.UpdateDeal ## Access & visibility Allow `customers.UpdateDeal` on your API key. Resource read permissions: `core:Deal`. Resource write permissions: `core:Deal`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:Deal` record. Find it with [customers.ListDeals](/developers/reference/customers/ListDeals). Use the record's top-level `id`, not a business field or account ID. | | `data` | [Deal](#deal-request-data) | No | The fields to set. | | `unset` | array of string | No | Keys of `data` to remove. Each item: `"title"`, `"stage"`, `"amount_ore"`, `"product_lines"`, `"company_ref"`, `"contact_ref"`, `"owner_ref"`, `"expected_close_date"`, `"description"`, `"lost_reason"`, `"tags"`. | | `expected` | [object](#request-expected) | No | Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {"$absent":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource. | ### Deal · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string | No | Name of the sales opportunity. | | `stage` | string | No | A stage id from the org's own sales pipeline, in funnel order: lead = Lead, qualified = Qualified, proposal = Proposal, negotiation = Negotiation, won = Won (won), lost = Lost (lost). The list is the org's to change — the pipeline is the `core:SalesPipeline` entry (edit its `stages` to add, rename, reorder or re-weight a stage; the ids here follow). Allowed: `"lead"`, `"qualified"`, `"proposal"`, `"negotiation"`, `"won"`, `"lost"`. | | `amount_ore` | integer | No | Value of the opportunity in Norwegian øre. 1000000 is NOK 10,000. Deals are NOK-only; do not supply another currency. | | `product_lines` | array of [object](#request-data-product-lines) | No | Products or services proposed in this deal, with quantities, prices and billing frequency. | | `company_ref` | string | No | ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name. | | `contact_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `owner_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `expected_close_date` | string | No | Expected date the opportunity will be won or lost, in YYYY-MM-DD format. | | `description` | string | No | Business context for the sales opportunity. | | `lost_reason` | string | No | Reason recorded when the opportunity is lost. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | ### request.data.product_lines[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `product_ref` | string | No | Product record ID. | | `name` | string | Yes | Display name. | | `description` | string | No | Descriptive text. | | `quantity` | number | No | Number of units. May be fractional when the product allows it. Minimum: 0. | | `unit` | string | No | Unit used for the quantity, such as hours or items. | | `unit_price_ore` | integer | No | Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only. | | `agreed_at` | number | No | Time the commercial terms were agreed, in Unix milliseconds. | | `agreed_deal_ref` | string | No | Deal record ID. | | `revenue_type` | string | No | Whether this amount is charged once or repeats monthly, quarterly or annually. Allowed: `"one_time"`, `"monthly"`, `"quarterly"`, `"annual"`. | | `start_date` | string | No | ISO date (YYYY-MM-DD) | | `end_date` | string | No | ISO date (YYYY-MM-DD) | ### request.expected | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string or [object](#request-expected-title) | No | Commit only if the previous title value matches; use $absent to require that this field is missing. | | `stage` | string or [object](#request-expected-stage) | No | Commit only if the previous stage value matches; use $absent to require that this field is missing. | | `amount_ore` | integer or [object](#request-expected-amount-ore) | No | Commit only if the previous amount_ore value matches; use $absent to require that this field is missing. | | `product_lines` | array of [object](#request-expected-product-lines) or [object](#request-expected-product-lines) | No | Commit only if the previous product_lines value matches; use $absent to require that this field is missing. | | `company_ref` | string or [object](#request-expected-company-ref) | No | Commit only if the previous company_ref value matches; use $absent to require that this field is missing. | | `contact_ref` | string or [object](#request-expected-contact-ref) | No | Commit only if the previous contact_ref value matches; use $absent to require that this field is missing. | | `owner_ref` | string or [object](#request-expected-owner-ref) | No | Commit only if the previous owner_ref value matches; use $absent to require that this field is missing. | | `expected_close_date` | string or [object](#request-expected-expected-close-date) | No | Commit only if the previous expected_close_date value matches; use $absent to require that this field is missing. | | `description` | string or [object](#request-expected-description) | No | Commit only if the previous description value matches; use $absent to require that this field is missing. | | `lost_reason` | string or [object](#request-expected-lost-reason) | No | Commit only if the previous lost_reason value matches; use $absent to require that this field is missing. | | `tags` | array of string or [object](#request-expected-tags) | No | Commit only if the previous tags value matches; use $absent to require that this field is missing. | ### request.expected.title | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.stage | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.amount_ore | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.product_lines | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.product_lines[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `product_ref` | string | No | Product record ID. | | `name` | string | Yes | Display name. | | `description` | string | No | Descriptive text. | | `quantity` | number | No | Number of units. May be fractional when the product allows it. Minimum: 0. | | `unit` | string | No | Unit used for the quantity, such as hours or items. | | `unit_price_ore` | integer | No | Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only. | | `agreed_at` | number | No | Time the commercial terms were agreed, in Unix milliseconds. | | `agreed_deal_ref` | string | No | Deal record ID. | | `revenue_type` | string | No | Whether this amount is charged once or repeats monthly, quarterly or annually. Allowed: `"one_time"`, `"monthly"`, `"quarterly"`, `"annual"`. | | `start_date` | string | No | ISO date (YYYY-MM-DD) | | `end_date` | string | No | ISO date (YYYY-MM-DD) | ### request.expected.company_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.contact_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.owner_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.expected_close_date | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.description | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.lost_reason | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.tags | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ## Update without losing changes Send only the business fields you want to change in `data`; omitted fields stay unchanged. Use `unset` to remove an optional field. Setting a field to null is a different action and is allowed only when its schema permits null. Use `expected` for a conditional update: supply the values you last read for the fields whose concurrent changes would matter. `{"$absent": true}` expects a missing field. A conflict means you must read the record again and decide how to reconcile the change. Keep the same idempotency key when retrying the original action; use a new key for a revised action. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. The public schema lists accepted stage IDs. Labels are presentation text; use the stable stage ID in calls. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [DealRecord](#dealrecord-response-item) | Yes | The requested record, including its metadata and data fields. | ### DealRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Deal record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Deal](#deal-response-item-data) | Yes | The record's fields. | ### Deal · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string | Yes | Name of the sales opportunity. | | `stage` | string | Yes | A stage id from the org's own sales pipeline, in funnel order: lead = Lead, qualified = Qualified, proposal = Proposal, negotiation = Negotiation, won = Won (won), lost = Lost (lost). The list is the org's to change — the pipeline is the `core:SalesPipeline` entry (edit its `stages` to add, rename, reorder or re-weight a stage; the ids here follow). Allowed: `"lead"`, `"qualified"`, `"proposal"`, `"negotiation"`, `"won"`, `"lost"`. | | `amount_ore` | integer | No | Value of the opportunity in Norwegian øre. 1000000 is NOK 10,000. Deals are NOK-only; do not supply another currency. | | `product_lines` | array of [object](#response-item-data-product-lines) | No | Products or services proposed in this deal, with quantities, prices and billing frequency. | | `company_ref` | string | No | ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name. | | `contact_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `owner_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `expected_close_date` | string | No | Expected date the opportunity will be won or lost, in YYYY-MM-DD format. | | `description` | string | No | Business context for the sales opportunity. | | `lost_reason` | string | No | Reason recorded when the opportunity is lost. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | ### response.item.data.product_lines[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `product_ref` | string | No | Product record ID. | | `name` | string | Yes | Display name. | | `description` | string | No | Descriptive text. | | `quantity` | number | No | Number of units. May be fractional when the product allows it. Minimum: 0. | | `unit` | string | No | Unit used for the quantity, such as hours or items. | | `unit_price_ore` | integer | No | Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only. | | `agreed_at` | number | No | Time the commercial terms were agreed, in Unix milliseconds. | | `agreed_deal_ref` | string | No | Deal record ID. | | `revenue_type` | string | No | Whether this amount is charged once or repeats monthly, quarterly or annually. Allowed: `"one_time"`, `"monthly"`, `"quarterly"`, `"annual"`. | | `start_date` | string | No | ISO date (YYYY-MM-DD) | | `end_date` | string | No | ISO date (YYYY-MM-DD) | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `conflict` | A supplied expected value no longer matches. Read the record again before deciding whether to retry. | ## Next steps - [List deals](/developers/reference/customers/ListDeals) - [Get deal](/developers/reference/customers/GetDeal) - [Create deal](/developers/reference/customers/CreateDeal) - [Upsert deal](/developers/reference/customers/UpsertDeal) - [Delete deal](/developers/reference/customers/DeleteDeal) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.UpdateDeal' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_deal_example", "data": { "stage": "won" } }' ``` #### TypeScript ```typescript 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/customers.UpdateDeal", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_deal_example", "data": { "stage": "won" } }), }); 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_deal_example", "data": { "stage": "won" } } request = Request( "https://api.brigg.app/v1/operations/customers.UpdateDeal", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_deal_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "title": "Customer onboarding project", "stage": "won", "amount_ore": 1000000, "company_ref": "e_company_example", "contact_ref": "e_person_example", "expected_close_date": "2026-11-30" } } } ``` ### Update only if unchanged Use a value you actually read. A concurrent change refuses the write with 409 conflict. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.UpdateDeal' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_deal_example", "data": { "stage": "won" }, "expected": { "title": "Customer onboarding project" } }' ``` #### TypeScript ```typescript 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/customers.UpdateDeal", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_deal_example", "data": { "stage": "won" }, "expected": { "title": "Customer onboarding project" } }), }); 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_deal_example", "data": { "stage": "won" }, "expected": { "title": "Customer onboarding project" } } request = Request( "https://api.brigg.app/v1/operations/customers.UpdateDeal", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_deal_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "title": "Customer onboarding project", "stage": "won", "amount_ore": 1000000, "company_ref": "e_company_example", "contact_ref": "e_person_example", "expected_close_date": "2026-11-30" } } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:Deal` record. Find it with [customers.ListDeals](/developers/reference/customers/ListDeals). Use the record's top-level `id`, not a business field or account ID." }, "data": { "type": "object", "properties": { "title": { "type": "string", "description": "Name of the sales opportunity." }, "stage": { "type": "string", "enum": [ "lead", "qualified", "proposal", "negotiation", "won", "lost" ], "description": "A stage id from the org's own sales pipeline, in funnel order: lead = Lead, qualified = Qualified, proposal = Proposal, negotiation = Negotiation, won = Won (won), lost = Lost (lost). The list is the org's to change — the pipeline is the `core:SalesPipeline` entry (edit its `stages` to add, rename, reorder or re-weight a stage; the ids here follow)." }, "amount_ore": { "type": "integer", "description": "Value of the opportunity in Norwegian øre. 1000000 is NOK 10,000. Deals are NOK-only; do not supply another currency." }, "product_lines": { "type": "array", "items": { "type": "object", "properties": { "product_ref": { "type": "string", "description": "Product record ID." }, "name": { "type": "string", "description": "Display name." }, "description": { "type": "string", "description": "Descriptive text." }, "quantity": { "type": "number", "minimum": 0, "description": "Number of units. May be fractional when the product allows it." }, "unit": { "type": "string", "description": "Unit used for the quantity, such as hours or items." }, "unit_price_ore": { "type": "integer", "description": "Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only." }, "agreed_at": { "type": "number", "description": "Time the commercial terms were agreed, in Unix milliseconds." }, "agreed_deal_ref": { "type": "string", "description": "Deal record ID." }, "revenue_type": { "type": "string", "enum": [ "one_time", "monthly", "quarterly", "annual" ], "description": "Whether this amount is charged once or repeats monthly, quarterly or annually." }, "start_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" }, "end_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" } }, "required": [ "name" ], "additionalProperties": false }, "description": "Products or services proposed in this deal, with quantities, prices and billing frequency." }, "company_ref": { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." }, "contact_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "owner_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "expected_close_date": { "type": "string", "description": "Expected date the opportunity will be won or lost, in YYYY-MM-DD format." }, "description": { "type": "string", "description": "Business context for the sales opportunity." }, "lost_reason": { "type": "string", "description": "Reason recorded when the opportunity is lost." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." } }, "required": [], "additionalProperties": false, "description": "The fields to set.", "title": "Deal" }, "unset": { "type": "array", "items": { "type": "string", "enum": [ "title", "stage", "amount_ore", "product_lines", "company_ref", "contact_ref", "owner_ref", "expected_close_date", "description", "lost_reason", "tags" ] }, "description": "Keys of `data` to remove." }, "expected": { "type": "object", "description": "Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {\"$absent\":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource.", "additionalProperties": false, "properties": { "title": { "description": "Commit only if the previous title value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Name of the sales opportunity." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "stage": { "description": "Commit only if the previous stage value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "enum": [ "lead", "qualified", "proposal", "negotiation", "won", "lost" ], "description": "A stage id from the org's own sales pipeline, in funnel order: lead = Lead, qualified = Qualified, proposal = Proposal, negotiation = Negotiation, won = Won (won), lost = Lost (lost). The list is the org's to change — the pipeline is the `core:SalesPipeline` entry (edit its `stages` to add, rename, reorder or re-weight a stage; the ids here follow)." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "amount_ore": { "description": "Commit only if the previous amount_ore value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "integer", "description": "Value of the opportunity in Norwegian øre. 1000000 is NOK 10,000. Deals are NOK-only; do not supply another currency." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "product_lines": { "description": "Commit only if the previous product_lines value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "type": "object", "properties": { "product_ref": { "type": "string", "description": "Product record ID." }, "name": { "type": "string", "description": "Display name." }, "description": { "type": "string", "description": "Descriptive text." }, "quantity": { "type": "number", "minimum": 0, "description": "Number of units. May be fractional when the product allows it." }, "unit": { "type": "string", "description": "Unit used for the quantity, such as hours or items." }, "unit_price_ore": { "type": "integer", "description": "Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only." }, "agreed_at": { "type": "number", "description": "Time the commercial terms were agreed, in Unix milliseconds." }, "agreed_deal_ref": { "type": "string", "description": "Deal record ID." }, "revenue_type": { "type": "string", "enum": [ "one_time", "monthly", "quarterly", "annual" ], "description": "Whether this amount is charged once or repeats monthly, quarterly or annually." }, "start_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" }, "end_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" } }, "required": [ "name" ], "additionalProperties": false }, "description": "Products or services proposed in this deal, with quantities, prices and billing frequency." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "company_ref": { "description": "Commit only if the previous company_ref value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "contact_ref": { "description": "Commit only if the previous contact_ref value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "owner_ref": { "description": "Commit only if the previous owner_ref value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "expected_close_date": { "description": "Commit only if the previous expected_close_date value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Expected date the opportunity will be won or lost, in YYYY-MM-DD format." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "description": { "description": "Commit only if the previous description value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Business context for the sales opportunity." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "lost_reason": { "description": "Commit only if the previous lost_reason value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Reason recorded when the opportunity is lost." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "tags": { "description": "Commit only if the previous tags value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] } } } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_deal_example", "data": { "stage": "won" } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:Deal record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "title": { "type": "string", "description": "Name of the sales opportunity." }, "stage": { "type": "string", "enum": [ "lead", "qualified", "proposal", "negotiation", "won", "lost" ], "description": "A stage id from the org's own sales pipeline, in funnel order: lead = Lead, qualified = Qualified, proposal = Proposal, negotiation = Negotiation, won = Won (won), lost = Lost (lost). The list is the org's to change — the pipeline is the `core:SalesPipeline` entry (edit its `stages` to add, rename, reorder or re-weight a stage; the ids here follow)." }, "amount_ore": { "type": "integer", "description": "Value of the opportunity in Norwegian øre. 1000000 is NOK 10,000. Deals are NOK-only; do not supply another currency." }, "product_lines": { "type": "array", "items": { "type": "object", "properties": { "product_ref": { "type": "string", "description": "Product record ID." }, "name": { "type": "string", "description": "Display name." }, "description": { "type": "string", "description": "Descriptive text." }, "quantity": { "type": "number", "minimum": 0, "description": "Number of units. May be fractional when the product allows it." }, "unit": { "type": "string", "description": "Unit used for the quantity, such as hours or items." }, "unit_price_ore": { "type": "integer", "description": "Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only." }, "agreed_at": { "type": "number", "description": "Time the commercial terms were agreed, in Unix milliseconds." }, "agreed_deal_ref": { "type": "string", "description": "Deal record ID." }, "revenue_type": { "type": "string", "enum": [ "one_time", "monthly", "quarterly", "annual" ], "description": "Whether this amount is charged once or repeats monthly, quarterly or annually." }, "start_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" }, "end_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" } }, "required": [ "name" ], "additionalProperties": false }, "description": "Products or services proposed in this deal, with quantities, prices and billing frequency." }, "company_ref": { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." }, "contact_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "owner_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "expected_close_date": { "type": "string", "description": "Expected date the opportunity will be won or lost, in YYYY-MM-DD format." }, "description": { "type": "string", "description": "Business context for the sales opportunity." }, "lost_reason": { "type": "string", "description": "Reason recorded when the opportunity is lost." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." } }, "required": [ "title", "stage" ], "additionalProperties": false, "description": "The record's fields.", "title": "Deal" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "DealRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_deal_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "title": "Customer onboarding project", "stage": "won", "amount_ore": 1000000, "company_ref": "e_company_example", "contact_ref": "e_person_example", "expected_close_date": "2026-11-30" } } } ] } ``` --- # Upsert deal Create or update a deal by a permanent external reference. Matching is exact within the workspace, resource type and ownership scope. Supplied fields replace their values; omitted fields stay unchanged. Deleted records are not recreated. POST https://api.brigg.app/v1/operations/customers.UpsertDeal ## Access & visibility Allow `customers.UpsertDeal` on your API key. Resource read permissions: `core:Deal`. Resource write permissions: `core:Deal`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `data` | [Deal](#deal-request-data) | Yes | The record's fields. | | `private` | boolean | No | Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance. | | `external_ref` | [object](#request-external-ref) | Yes | Permanent, case-sensitive source identity within this workspace, resource type and private/workspace scope. It is independent of API key rotation and retry receipt expiry. | ### Deal · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string | Yes | Name of the sales opportunity. | | `stage` | string | Yes | A stage id from the org's own sales pipeline, in funnel order: lead = Lead, qualified = Qualified, proposal = Proposal, negotiation = Negotiation, won = Won (won), lost = Lost (lost). The list is the org's to change — the pipeline is the `core:SalesPipeline` entry (edit its `stages` to add, rename, reorder or re-weight a stage; the ids here follow). Allowed: `"lead"`, `"qualified"`, `"proposal"`, `"negotiation"`, `"won"`, `"lost"`. | | `amount_ore` | integer | No | Value of the opportunity in Norwegian øre. 1000000 is NOK 10,000. Deals are NOK-only; do not supply another currency. | | `product_lines` | array of [object](#request-data-product-lines) | No | Products or services proposed in this deal, with quantities, prices and billing frequency. | | `company_ref` | string | No | ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name. | | `contact_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `owner_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `expected_close_date` | string | No | Expected date the opportunity will be won or lost, in YYYY-MM-DD format. | | `description` | string | No | Business context for the sales opportunity. | | `lost_reason` | string | No | Reason recorded when the opportunity is lost. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | ### request.data.product_lines[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `product_ref` | string | No | Product record ID. | | `name` | string | Yes | Display name. | | `description` | string | No | Descriptive text. | | `quantity` | number | No | Number of units. May be fractional when the product allows it. Minimum: 0. | | `unit` | string | No | Unit used for the quantity, such as hours or items. | | `unit_price_ore` | integer | No | Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only. | | `agreed_at` | number | No | Time the commercial terms were agreed, in Unix milliseconds. | | `agreed_deal_ref` | string | No | Deal record ID. | | `revenue_type` | string | No | Whether this amount is charged once or repeats monthly, quarterly or annually. Allowed: `"one_time"`, `"monthly"`, `"quarterly"`, `"annual"`. | | `start_date` | string | No | ISO date (YYYY-MM-DD) | | `end_date` | string | No | ISO date (YYYY-MM-DD) | ### request.external_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `namespace` | string | Yes | A stable name for the source system, such as crm-production. At least 1 character. | | `id` | string | Yes | The record ID in that source system. At least 1 character. | ## Sync with a permanent external reference Choose a stable `external_ref.namespace` for your source system and put its record ID in `external_ref.id`. Matching is case-sensitive and scoped to this workspace, resource type and private/workspace ownership. The reference survives API key replacement and the 30-day retry receipt window. It does not match records by email or name. Send the required create fields each time. A missing reference creates a record; an existing reference updates only supplied fields and preserves everything else. `created` tells you which happened. Use the same idempotency key when retrying a lost response and a new key for a later source change. Concurrent calls cannot create duplicate records. A deleted or inaccessible match is refused; the operation does not restore it or make a replacement. Use the returned `item.id` with the regular update operation when you need `unset` or a conditional `expected` edit. Changing `private` chooses a different ownership scope; it does not transfer an existing record. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. The public schema lists accepted stage IDs. Labels are presentation text; use the stable stage ID in calls. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [DealRecord](#dealrecord-response-item) | Yes | The requested record, including its metadata and data fields. | | `created` | boolean | Yes | True when this external reference created a record; false when it matched an existing record. | ### DealRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Deal record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Deal](#deal-response-item-data) | Yes | The record's fields. | ### Deal · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string | Yes | Name of the sales opportunity. | | `stage` | string | Yes | A stage id from the org's own sales pipeline, in funnel order: lead = Lead, qualified = Qualified, proposal = Proposal, negotiation = Negotiation, won = Won (won), lost = Lost (lost). The list is the org's to change — the pipeline is the `core:SalesPipeline` entry (edit its `stages` to add, rename, reorder or re-weight a stage; the ids here follow). Allowed: `"lead"`, `"qualified"`, `"proposal"`, `"negotiation"`, `"won"`, `"lost"`. | | `amount_ore` | integer | No | Value of the opportunity in Norwegian øre. 1000000 is NOK 10,000. Deals are NOK-only; do not supply another currency. | | `product_lines` | array of [object](#response-item-data-product-lines) | No | Products or services proposed in this deal, with quantities, prices and billing frequency. | | `company_ref` | string | No | ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name. | | `contact_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `owner_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `expected_close_date` | string | No | Expected date the opportunity will be won or lost, in YYYY-MM-DD format. | | `description` | string | No | Business context for the sales opportunity. | | `lost_reason` | string | No | Reason recorded when the opportunity is lost. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | ### response.item.data.product_lines[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `product_ref` | string | No | Product record ID. | | `name` | string | Yes | Display name. | | `description` | string | No | Descriptive text. | | `quantity` | number | No | Number of units. May be fractional when the product allows it. Minimum: 0. | | `unit` | string | No | Unit used for the quantity, such as hours or items. | | `unit_price_ore` | integer | No | Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only. | | `agreed_at` | number | No | Time the commercial terms were agreed, in Unix milliseconds. | | `agreed_deal_ref` | string | No | Deal record ID. | | `revenue_type` | string | No | Whether this amount is charged once or repeats monthly, quarterly or annually. Allowed: `"one_time"`, `"monthly"`, `"quarterly"`, `"annual"`. | | `start_date` | string | No | ISO date (YYYY-MM-DD) | | `end_date` | string | No | ISO date (YYYY-MM-DD) | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List deals](/developers/reference/customers/ListDeals) - [Get deal](/developers/reference/customers/GetDeal) - [Create deal](/developers/reference/customers/CreateDeal) - [Update deal](/developers/reference/customers/UpdateDeal) - [Delete deal](/developers/reference/customers/DeleteDeal) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### First sync Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.UpsertDeal' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "title": "Customer onboarding project", "stage": "proposal", "amount_ore": 1000000, "company_ref": "e_company_example", "contact_ref": "e_person_example", "expected_close_date": "2026-11-30" } }' ``` #### TypeScript ```typescript 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/customers.UpsertDeal", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "title": "Customer onboarding project", "stage": "proposal", "amount_ore": 1000000, "company_ref": "e_company_example", "contact_ref": "e_person_example", "expected_close_date": "2026-11-30" } }), }); 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 = { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "title": "Customer onboarding project", "stage": "proposal", "amount_ore": 1000000, "company_ref": "e_company_example", "contact_ref": "e_person_example", "expected_close_date": "2026-11-30" } } request = Request( "https://api.brigg.app/v1/operations/customers.UpsertDeal", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_deal_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "title": "Customer onboarding project", "stage": "proposal", "amount_ore": 1000000, "company_ref": "e_company_example", "contact_ref": "e_person_example", "expected_close_date": "2026-11-30" } }, "created": true } ``` ### Later sync The same external reference returns the same record ID. Use a new idempotency key for a later source change. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.UpsertDeal' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "title": "Customer onboarding project", "stage": "proposal", "amount_ore": 1000000, "company_ref": "e_company_example", "contact_ref": "e_person_example", "expected_close_date": "2026-11-30" } }' ``` #### TypeScript ```typescript 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/customers.UpsertDeal", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "title": "Customer onboarding project", "stage": "proposal", "amount_ore": 1000000, "company_ref": "e_company_example", "contact_ref": "e_person_example", "expected_close_date": "2026-11-30" } }), }); 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 = { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "title": "Customer onboarding project", "stage": "proposal", "amount_ore": 1000000, "company_ref": "e_company_example", "contact_ref": "e_person_example", "expected_close_date": "2026-11-30" } } request = Request( "https://api.brigg.app/v1/operations/customers.UpsertDeal", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_deal_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "title": "Customer onboarding project", "stage": "proposal", "amount_ore": 1000000, "company_ref": "e_company_example", "contact_ref": "e_person_example", "expected_close_date": "2026-11-30" } }, "created": false } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "data": { "type": "object", "properties": { "title": { "type": "string", "description": "Name of the sales opportunity." }, "stage": { "type": "string", "enum": [ "lead", "qualified", "proposal", "negotiation", "won", "lost" ], "description": "A stage id from the org's own sales pipeline, in funnel order: lead = Lead, qualified = Qualified, proposal = Proposal, negotiation = Negotiation, won = Won (won), lost = Lost (lost). The list is the org's to change — the pipeline is the `core:SalesPipeline` entry (edit its `stages` to add, rename, reorder or re-weight a stage; the ids here follow)." }, "amount_ore": { "type": "integer", "description": "Value of the opportunity in Norwegian øre. 1000000 is NOK 10,000. Deals are NOK-only; do not supply another currency." }, "product_lines": { "type": "array", "items": { "type": "object", "properties": { "product_ref": { "type": "string", "description": "Product record ID." }, "name": { "type": "string", "description": "Display name." }, "description": { "type": "string", "description": "Descriptive text." }, "quantity": { "type": "number", "minimum": 0, "description": "Number of units. May be fractional when the product allows it." }, "unit": { "type": "string", "description": "Unit used for the quantity, such as hours or items." }, "unit_price_ore": { "type": "integer", "description": "Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only." }, "agreed_at": { "type": "number", "description": "Time the commercial terms were agreed, in Unix milliseconds." }, "agreed_deal_ref": { "type": "string", "description": "Deal record ID." }, "revenue_type": { "type": "string", "enum": [ "one_time", "monthly", "quarterly", "annual" ], "description": "Whether this amount is charged once or repeats monthly, quarterly or annually." }, "start_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" }, "end_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" } }, "required": [ "name" ], "additionalProperties": false }, "description": "Products or services proposed in this deal, with quantities, prices and billing frequency." }, "company_ref": { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." }, "contact_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "owner_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "expected_close_date": { "type": "string", "description": "Expected date the opportunity will be won or lost, in YYYY-MM-DD format." }, "description": { "type": "string", "description": "Business context for the sales opportunity." }, "lost_reason": { "type": "string", "description": "Reason recorded when the opportunity is lost." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." } }, "required": [ "title", "stage" ], "additionalProperties": false, "description": "The record's fields.", "title": "Deal" }, "private": { "type": "boolean", "description": "Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance." }, "external_ref": { "type": "object", "description": "Permanent, case-sensitive source identity within this workspace, resource type and private/workspace scope. It is independent of API key rotation and retry receipt expiry.", "properties": { "namespace": { "type": "string", "minLength": 1, "description": "A stable name for the source system, such as crm-production." }, "id": { "type": "string", "minLength": 1, "description": "The record ID in that source system." } }, "required": [ "namespace", "id" ], "additionalProperties": false } }, "required": [ "external_ref", "data" ], "additionalProperties": false, "examples": [ { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "title": "Customer onboarding project", "stage": "proposal", "amount_ore": 1000000, "company_ref": "e_company_example", "contact_ref": "e_person_example", "expected_close_date": "2026-11-30" } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:Deal record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "title": { "type": "string", "description": "Name of the sales opportunity." }, "stage": { "type": "string", "enum": [ "lead", "qualified", "proposal", "negotiation", "won", "lost" ], "description": "A stage id from the org's own sales pipeline, in funnel order: lead = Lead, qualified = Qualified, proposal = Proposal, negotiation = Negotiation, won = Won (won), lost = Lost (lost). The list is the org's to change — the pipeline is the `core:SalesPipeline` entry (edit its `stages` to add, rename, reorder or re-weight a stage; the ids here follow)." }, "amount_ore": { "type": "integer", "description": "Value of the opportunity in Norwegian øre. 1000000 is NOK 10,000. Deals are NOK-only; do not supply another currency." }, "product_lines": { "type": "array", "items": { "type": "object", "properties": { "product_ref": { "type": "string", "description": "Product record ID." }, "name": { "type": "string", "description": "Display name." }, "description": { "type": "string", "description": "Descriptive text." }, "quantity": { "type": "number", "minimum": 0, "description": "Number of units. May be fractional when the product allows it." }, "unit": { "type": "string", "description": "Unit used for the quantity, such as hours or items." }, "unit_price_ore": { "type": "integer", "description": "Price per unit in Norwegian øre; 100000 is NOK 1,000. Product lines use NOK only." }, "agreed_at": { "type": "number", "description": "Time the commercial terms were agreed, in Unix milliseconds." }, "agreed_deal_ref": { "type": "string", "description": "Deal record ID." }, "revenue_type": { "type": "string", "enum": [ "one_time", "monthly", "quarterly", "annual" ], "description": "Whether this amount is charged once or repeats monthly, quarterly or annually." }, "start_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" }, "end_date": { "type": "string", "description": "ISO date (YYYY-MM-DD)" } }, "required": [ "name" ], "additionalProperties": false }, "description": "Products or services proposed in this deal, with quantities, prices and billing frequency." }, "company_ref": { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." }, "contact_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "owner_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "expected_close_date": { "type": "string", "description": "Expected date the opportunity will be won or lost, in YYYY-MM-DD format." }, "description": { "type": "string", "description": "Business context for the sales opportunity." }, "lost_reason": { "type": "string", "description": "Reason recorded when the opportunity is lost." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." } }, "required": [ "title", "stage" ], "additionalProperties": false, "description": "The record's fields.", "title": "Deal" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "DealRecord" }, "created": { "type": "boolean", "description": "True when this external reference created a record; false when it matched an existing record." } }, "required": [ "item", "created" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_deal_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "title": "Customer onboarding project", "stage": "proposal", "amount_ore": 1000000, "company_ref": "e_company_example", "contact_ref": "e_person_example", "expected_close_date": "2026-11-30" } }, "created": true } ] } ``` --- # Get email message Read an archived email record. The record is a copy of correspondence, not a message draft or an instruction to send mail. POST https://api.brigg.app/v1/operations/customers.GetEmailMessage ## Access & visibility Allow `customers.GetEmailMessage` on your API key. Resource read permissions: `core:EmailMessage`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:EmailMessage` record. Use the relevant list operation to discover records. Use the record's top-level `id`, not a business field or account ID. | ## Response Returns **200 OK** with a JSON body. `item: null` means there is no matching record visible to this caller. It does not reveal whether an inaccessible record exists. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. This is a read-only email activity record. Listing it neither sends an email nor returns full mailbox access. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [EmailMessageRecord](#emailmessagerecord-response-item) or null | Yes | null when no such record | ### EmailMessageRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:EmailMessage record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [EmailMessage](#emailmessage-response-item-data) | Yes | The record's fields. | ### EmailMessage · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `channel` | string | No | Communication channel recorded for this message. | | `subject` | string | Yes | Email subject line. | | `sent_at` | number | Yes | Time the message was sent, in Unix milliseconds. | | `recipients` | array of string | No | Recipient addresses recorded for this email. | | `contact_refs` | array of string | No | Person record IDs linked to this message. | | `company_refs` | array of string | No | Company record IDs linked to this message. | | `sender_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `email_id` | string | No | Identifier of the underlying email, distinct from this timeline record's ID. | | `attachment_file_ids` | array of string | No | File IDs for email attachments; use the file download API with the caller's current access. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [List email messages](/developers/reference/customers/ListEmailMessages) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.GetEmailMessage' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "e_emailmessage_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.GetEmailMessage", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "id": "e_emailmessage_example" }), }); 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 payload = { "id": "e_emailmessage_example" } request = Request( "https://api.brigg.app/v1/operations/customers.GetEmailMessage", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "item": { "id": "e_emailmessage_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "subject": "Pilot next steps", "sent_at": 1791279900000, "channel": "email", "recipients": [ "alex@example.org" ], "company_refs": [ "e_company_northstar" ] } } } ``` ### No visible record A missing or inaccessible record returns item: null. Do not treat this as proof that a record exists for another member. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.GetEmailMessage' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "e_emailmessage_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.GetEmailMessage", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "id": "e_emailmessage_example" }), }); 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 payload = { "id": "e_emailmessage_example" } request = Request( "https://api.brigg.app/v1/operations/customers.GetEmailMessage", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "item": null } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:EmailMessage` record. Use the relevant list operation to discover records. Use the record's top-level `id`, not a business field or account ID." } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_emailmessage_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": [ "object", "null" ], "properties": { "id": { "type": "string", "description": "Stable core:EmailMessage record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "channel": { "type": "string", "description": "Communication channel recorded for this message." }, "subject": { "type": "string", "description": "Email subject line." }, "sent_at": { "type": "number", "description": "Time the message was sent, in Unix milliseconds." }, "recipients": { "type": "array", "items": { "type": "string" }, "description": "Recipient addresses recorded for this email." }, "contact_refs": { "type": "array", "items": { "type": "string", "description": "id of a core:Person" }, "description": "Person record IDs linked to this message." }, "company_refs": { "type": "array", "items": { "type": "string", "description": "id of a core:Company" }, "description": "Company record IDs linked to this message." }, "sender_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "email_id": { "type": "string", "description": "Identifier of the underlying email, distinct from this timeline record's ID." }, "attachment_file_ids": { "type": "array", "items": { "type": "string" }, "description": "File IDs for email attachments; use the file download API with the caller's current access." } }, "required": [ "subject", "sent_at" ], "additionalProperties": false, "description": "The record's fields.", "title": "EmailMessage" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "null when no such record", "title": "EmailMessageRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_emailmessage_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "subject": "Pilot next steps", "sent_at": 1791279900000, "channel": "email", "recipients": [ "alex@example.org" ], "company_refs": [ "e_company_northstar" ] } } } ] } ``` --- # List email messages List archived email records visible to the caller. These are history records; reading or editing related customer records does not send email. POST https://api.brigg.app/v1/operations/customers.ListEmailMessages ## Access & visibility Allow `customers.ListEmailMessages` on your API key. Resource read permissions: `core:EmailMessage`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `filters` | array of [object](#request-filters) | No | Conditions the row must ALL satisfy. | | `sort` | [object](#request-sort) | No | Sort order for the results. Defaults to updated_at descending, with id as a tie-breaker. | | `limit` | integer | No | Maximum number of results to return in this page. Continue with next_cursor when returned. Default: `100`. Minimum: 1. | | `cursor` | string | No | The `next_cursor` of the previous page. | ### request.filters[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | `data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private. Allowed: `"id"`, `"created_at"`, `"updated_at"`, `"created_by"`, `"private"`, `"data.channel"`, `"data.subject"`, `"data.sent_at"`, `"data.recipients"`, `"data.contact_refs"`, `"data.company_refs"`, `"data.sender_ref"`, `"data.email_id"`, `"data.attachment_file_ids"`. | | `op` | string | Yes | Comparison operator. Use in with an array, or omit value for is_empty and is_not_empty. Allowed: `"eq"`, `"neq"`, `"contains"`, `"starts_with"`, `"gt"`, `"gte"`, `"lt"`, `"lte"`, `"in"`, `"has"`, `"is_empty"`, `"is_not_empty"`. | | `value` | JSON value | No | The comparison value; an array for `in`; omitted for is_empty / is_not_empty. | ### request.sort | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | `data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private. Allowed: `"id"`, `"created_at"`, `"updated_at"`, `"created_by"`, `"private"`, `"data.channel"`, `"data.subject"`, `"data.sent_at"`, `"data.recipients"`, `"data.contact_refs"`, `"data.company_refs"`, `"data.sender_ref"`, `"data.email_id"`, `"data.attachment_file_ids"`. | | `direction` | string | No | Sort direction: asc for ascending or desc for descending. Allowed: `"asc"`, `"desc"`. | ## Filtering and sorting All conditions are combined with **AND**. Address business fields as `data.`, and record metadata as `id`, `created_at`, `updated_at`, `created_by` or `private`. A field path names one field; it does not traverse nested objects. | Operator | Meaning | Value | | --- | --- | --- | | `eq` | Equal to a scalar | String, number, boolean or null | | `neq` | Not equal; missing values also match | String, number, boolean or null | | `contains` | Case-insensitive text contains | String; % and _ are literal characters | | `starts_with` | Case-insensitive text prefix | String | | `gt`, `gte` | Greater than / at least | Number or string appropriate to the field | | `lt`, `lte` | Less than / at most | Number or string appropriate to the field | | `in` | Equal to any supplied scalar | Nonempty array of strings, numbers, booleans or null | | `has` | Array contains a string | One string; does not match properties inside array objects | | `is_empty` | Missing, null, empty string or empty array | Omit value | | `is_not_empty` | Has a nonempty value | Omit value | Match the stored field's type. Numeric business timestamps take Unix milliseconds; date-only business fields take `YYYY-MM-DD`. The record metadata fields `created_at` and `updated_at` also accept ISO timestamps for ordered comparisons. Sorting defaults to `updated_at` descending. If you supply `sort.field` without `sort.direction`, direction is `desc`. The record ID breaks ties; missing values sort last. ## Response Returns **200 OK** with a JSON body. An empty `items` array means this page contains no matching visible results. Follow `next_cursor` when present. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. This is a read-only email activity record. Listing it neither sends an email nor returns full mailbox access. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [EmailMessageRecord](#emailmessagerecord-response-items) | Yes | Records visible under the credential's grants and the selected data scope, matching the requested filters. Pass next_cursor as cursor to continue when a next cursor is returned. | | `next_cursor` | string | No | Pass this value as cursor to continue with the same filters, sort and credential. Omitted when there are no more results. | ### EmailMessageRecord · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:EmailMessage record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [EmailMessage](#emailmessage-response-items-data) | Yes | The record's fields. | ### EmailMessage · response.items[].data | Field | Type | Required | Description | | --- | --- | --- | --- | | `channel` | string | No | Communication channel recorded for this message. | | `subject` | string | Yes | Email subject line. | | `sent_at` | number | Yes | Time the message was sent, in Unix milliseconds. | | `recipients` | array of string | No | Recipient addresses recorded for this email. | | `contact_refs` | array of string | No | Person record IDs linked to this message. | | `company_refs` | array of string | No | Company record IDs linked to this message. | | `sender_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `email_id` | string | No | Identifier of the underlying email, distinct from this timeline record's ID. | | `attachment_file_ids` | array of string | No | File IDs for email attachments; use the file download API with the caller's current access. | ## Pagination Pass `next_cursor` from the response as `cursor` on the next request. Keep the same filters, sort and acting identity. Stop when `next_cursor` is absent; do not infer completion from the number of items. The default page size is **100**; `limit` must be a positive integer. **Pagination is a live view, not a snapshot.** Changes between pages can move records across page boundaries. Upsert by record ID rather than appending blindly. For recurring synchronization, use an overlapping update window and deduplicate records. Periodically reconcile IDs to detect deletions. [Resource webhooks](/developers/webhooks) can supplement synchronization for eligible workspace-shared records only: they do not export private or project-scoped records. Personal data still needs polling and reconciliation. ```typescript const query = { "limit": 10 }; let cursor; do { const response = await fetch("https://api.brigg.app/v1/operations/customers.ListEmailMessages", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ ...query, ...(cursor ? { cursor } : {}) }), }); const page = await response.json(); if (!response.ok) throw new Error(`${response.status}: ${page.message}`); for (const item of page.items) { console.log(item); // Process or upsert each result. } cursor = page.next_cursor; } while (cursor); ``` ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | | 400 | `cursor_invalid` | Restart pagination with no cursor. | | 400 | `cursor_mismatch` | Use the cursor with the original filters, sort order and credential. | ## Next steps - [Get email message](/developers/reference/customers/GetEmailMessage) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### First page Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.ListEmailMessages' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "limit": 10 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.ListEmailMessages", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "limit": 10 }), }); 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 payload = { "limit": 10 } request = Request( "https://api.brigg.app/v1/operations/customers.ListEmailMessages", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_emailmessage_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "subject": "Pilot next steps", "sent_at": 1791279900000, "channel": "email", "recipients": [ "alex@example.org" ], "company_refs": [ "e_company_northstar" ] } } ] } ``` ### Email activity for a company Use has for an array of Company record IDs. This reads timeline metadata, not a connected mailbox's full content. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.ListEmailMessages' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "limit": 50, "filters": [ { "field": "data.company_refs", "op": "has", "value": "e_company_northstar" } ] }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.ListEmailMessages", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "limit": 50, "filters": [ { "field": "data.company_refs", "op": "has", "value": "e_company_northstar" } ] }), }); 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 payload = { "limit": 50, "filters": [ { "field": "data.company_refs", "op": "has", "value": "e_company_northstar" } ] } request = Request( "https://api.brigg.app/v1/operations/customers.ListEmailMessages", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_emailmessage_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "subject": "Pilot next steps", "sent_at": 1791279900000, "channel": "email", "recipients": [ "alex@example.org" ], "company_refs": [ "e_company_northstar" ] } } ] } ``` ### Records updated since a checkpoint 6 October 2026 at 00:00 UTC. Use an overlap window and upsert by ID when synchronizing. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.ListEmailMessages' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.ListEmailMessages", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 }), }); 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 payload = { "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 } request = Request( "https://api.brigg.app/v1/operations/customers.ListEmailMessages", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_emailmessage_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "subject": "Pilot next steps", "sent_at": 1791279900000, "channel": "email", "recipients": [ "alex@example.org" ], "company_refs": [ "e_company_northstar" ] } } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "filters": { "type": "array", "items": { "type": "object", "properties": { "field": { "type": "string", "description": "`data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private.", "enum": [ "id", "created_at", "updated_at", "created_by", "private", "data.channel", "data.subject", "data.sent_at", "data.recipients", "data.contact_refs", "data.company_refs", "data.sender_ref", "data.email_id", "data.attachment_file_ids" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "contains", "starts_with", "gt", "gte", "lt", "lte", "in", "has", "is_empty", "is_not_empty" ], "description": "Comparison operator. Use in with an array, or omit value for is_empty and is_not_empty." }, "value": { "description": "The comparison value; an array for `in`; omitted for is_empty / is_not_empty." } }, "required": [ "field", "op" ], "additionalProperties": false }, "description": "Conditions the row must ALL satisfy." }, "sort": { "type": "object", "properties": { "field": { "type": "string", "description": "`data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private.", "enum": [ "id", "created_at", "updated_at", "created_by", "private", "data.channel", "data.subject", "data.sent_at", "data.recipients", "data.contact_refs", "data.company_refs", "data.sender_ref", "data.email_id", "data.attachment_file_ids" ] }, "direction": { "type": "string", "enum": [ "asc", "desc" ], "description": "Sort direction: asc for ascending or desc for descending." } }, "required": [ "field" ], "additionalProperties": false, "description": "Sort order for the results. Defaults to updated_at descending, with id as a tie-breaker." }, "limit": { "type": "integer", "minimum": 1, "default": 100, "description": "Maximum number of results to return in this page. Continue with next_cursor when returned." }, "cursor": { "type": "string", "description": "The `next_cursor` of the previous page." } }, "additionalProperties": false, "examples": [ { "limit": 10 } ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:EmailMessage record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "channel": { "type": "string", "description": "Communication channel recorded for this message." }, "subject": { "type": "string", "description": "Email subject line." }, "sent_at": { "type": "number", "description": "Time the message was sent, in Unix milliseconds." }, "recipients": { "type": "array", "items": { "type": "string" }, "description": "Recipient addresses recorded for this email." }, "contact_refs": { "type": "array", "items": { "type": "string", "description": "id of a core:Person" }, "description": "Person record IDs linked to this message." }, "company_refs": { "type": "array", "items": { "type": "string", "description": "id of a core:Company" }, "description": "Company record IDs linked to this message." }, "sender_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "email_id": { "type": "string", "description": "Identifier of the underlying email, distinct from this timeline record's ID." }, "attachment_file_ids": { "type": "array", "items": { "type": "string" }, "description": "File IDs for email attachments; use the file download API with the caller's current access." } }, "required": [ "subject", "sent_at" ], "additionalProperties": false, "description": "The record's fields.", "title": "EmailMessage" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "title": "EmailMessageRecord" }, "description": "Records visible under the credential's grants and the selected data scope, matching the requested filters. Pass next_cursor as cursor to continue when a next cursor is returned." }, "next_cursor": { "type": "string", "description": "Pass this value as cursor to continue with the same filters, sort and credential. Omitted when there are no more results." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "id": "e_emailmessage_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "subject": "Pilot next steps", "sent_at": 1791279900000, "channel": "email", "recipients": [ "alex@example.org" ], "company_refs": [ "e_company_northstar" ] } } ] } ] } ``` --- # Get CRM import run Read a CRM import’s progress and per-object counts. Created and updated counts describe records written; skipped records and limitations explain what was left out. Requires an owner or administrator. The same job ID can be used with workspace.GetJob by the person who started it. POST https://api.brigg.app/v1/operations/customers.GetCrmImportRun ## Access & visibility Allow `customers.GetCrmImportRun` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `job_id` | string | Yes | Run identifier. At least 1 character. | ## Import from a connected CRM Use [Get CRM import status](/developers/reference/customers/GetCrmImportStatus) to inspect the HubSpot connection, supported objects and the most recent run. [Preview CRM import](/developers/reference/customers/PreviewCrmImport) reads a sample without writing contacts. A missing provider scope requires reconnecting in Brigg; an API grant cannot supply missing provider consent. Start the connected-CRM import in Brigg. [Get CRM import run](/developers/reference/customers/GetCrmImportRun) reads its progress and detailed report. Review created, updated, skipped and not-imported counts; a finished run does not mean every source object was supported. To import through the public API, use [Start record import](/developers/reference/integrations/StartRecordImport) with a file and permanent external references. That workflow keeps the credential’s approved operation and resource permissions throughout background processing. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `job_id` | string | Yes | Run identifier. | | `status` | string | Yes | queued \| running \| done \| failed | | `progress_percent` | number | Yes | Progress pct. | | `phase` | string | No | Current phase of the background import or preparation job. | | `report` | [CrmImportReport](#crmimportreport-response-report) | Yes | Import counts, exclusions and limitations from the run. | | `started_at` | number | Yes | Time this work started, in Unix milliseconds. | | `completed_at` | number or null | No | Time this work completed, in Unix milliseconds. | ### CrmImportReport · response.report | Field | Type | Required | Description | | --- | --- | --- | --- | | `counts` | [object](#response-report-counts) | Yes | Per-object counts for the import. | | `limitations` | array of [object](#response-report-limitations) | Yes | Known exclusions or incomplete coverage in this import run. | | `portal` | [object](#response-report-portal) | No | Provider account or portal identifier used by this connection. | ### response.report.counts | Field | Type | Required | Description | | --- | --- | --- | --- | | `companies` | [object](#response-report-counts-companies) | No | Company records included in the import or search. | | `contacts` | [object](#response-report-counts-contacts) | No | Contact records included in the import. | | `deals` | [object](#response-report-counts-deals) | No | Sales opportunity records included in the import. | | `notes` | [object](#response-report-counts-notes) | No | Note records included in the import. | | `tasks` | [object](#response-report-counts-tasks) | No | Task records included in the import. | ### response.report.counts.companies | Field | Type | Required | Description | | --- | --- | --- | --- | | `scanned` | number | Yes | Source records examined by the import. | | `created` | number | Yes | Records newly created by the import, or whether this reusable item was newly created. | | `updated` | number | Yes | Existing records updated by the import. | | `skipped` | number | Yes | Source records left unchanged or not imported. | ### response.report.counts.contacts | Field | Type | Required | Description | | --- | --- | --- | --- | | `scanned` | number | Yes | Source records examined by the import. | | `created` | number | Yes | Records newly created by the import, or whether this reusable item was newly created. | | `updated` | number | Yes | Existing records updated by the import. | | `skipped` | number | Yes | Source records left unchanged or not imported. | ### response.report.counts.deals | Field | Type | Required | Description | | --- | --- | --- | --- | | `scanned` | number | Yes | Source records examined by the import. | | `created` | number | Yes | Records newly created by the import, or whether this reusable item was newly created. | | `updated` | number | Yes | Existing records updated by the import. | | `skipped` | number | Yes | Source records left unchanged or not imported. | ### response.report.counts.notes | Field | Type | Required | Description | | --- | --- | --- | --- | | `scanned` | number | Yes | Source records examined by the import. | | `created` | number | Yes | Records newly created by the import, or whether this reusable item was newly created. | | `updated` | number | Yes | Existing records updated by the import. | | `skipped` | number | Yes | Source records left unchanged or not imported. | ### response.report.counts.tasks | Field | Type | Required | Description | | --- | --- | --- | --- | | `scanned` | number | Yes | Source records examined by the import. | | `created` | number | Yes | Records newly created by the import, or whether this reusable item was newly created. | | `updated` | number | Yes | Existing records updated by the import. | | `skipped` | number | Yes | Source records left unchanged or not imported. | ### response.report.limitations[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `key` | string | Yes | Stable key identifying this option within its collection; distinct from its display label. | | `reason` | string | Yes | Explanation of why this outcome occurred. Allowed: `"missing_scope"`, `"no_equivalent"`, `"degraded"`, `"not_available"`. | | `detail` | string | No | Additional explanation of the reported result. | | `count` | number | No | Number of matching items represented by this result. | ### response.report.portal | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Unique identifier. Use the value returned by a create or list operation. | | `domain` | string | No | Website hostname, without a scheme or path. | | `currency` | string | No | Three-letter currency code, such as NOK, SEK or EUR. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [Get CRM import status](/developers/reference/customers/GetCrmImportStatus) - [Preview CRM import](/developers/reference/customers/PreviewCrmImport) - [Track the background job](/developers/reference/workspace/GetJob) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.GetCrmImportRun' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "job_id": "e_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.GetCrmImportRun", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "job_id": "e_example" }), }); 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 payload = { "job_id": "e_example" } request = Request( "https://api.brigg.app/v1/operations/customers.GetCrmImportRun", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "job_id": "e_example", "status": "completed", "progress_percent": 1, "report": { "counts": {}, "limitations": [] }, "started_at": 1794301200000 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "job_id": { "type": "string", "minLength": 1, "description": "Run identifier." } }, "required": [ "job_id" ], "additionalProperties": false, "examples": [ { "job_id": "e_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "job_id": { "type": "string", "description": "Run identifier." }, "status": { "type": "string", "description": "queued | running | done | failed" }, "progress_percent": { "type": "number", "description": "Progress pct." }, "phase": { "type": "string", "description": "Current phase of the background import or preparation job." }, "report": { "description": "Import counts, exclusions and limitations from the run.", "title": "CrmImportReport", "type": "object", "properties": { "counts": { "type": "object", "properties": { "companies": { "type": "object", "properties": { "scanned": { "type": "number", "description": "Source records examined by the import." }, "created": { "type": "number", "description": "Records newly created by the import, or whether this reusable item was newly created." }, "updated": { "type": "number", "description": "Existing records updated by the import." }, "skipped": { "type": "number", "description": "Source records left unchanged or not imported." } }, "required": [ "scanned", "created", "updated", "skipped" ], "additionalProperties": false, "description": "Company records included in the import or search." }, "contacts": { "type": "object", "properties": { "scanned": { "type": "number", "description": "Source records examined by the import." }, "created": { "type": "number", "description": "Records newly created by the import, or whether this reusable item was newly created." }, "updated": { "type": "number", "description": "Existing records updated by the import." }, "skipped": { "type": "number", "description": "Source records left unchanged or not imported." } }, "required": [ "scanned", "created", "updated", "skipped" ], "additionalProperties": false, "description": "Contact records included in the import." }, "deals": { "type": "object", "properties": { "scanned": { "type": "number", "description": "Source records examined by the import." }, "created": { "type": "number", "description": "Records newly created by the import, or whether this reusable item was newly created." }, "updated": { "type": "number", "description": "Existing records updated by the import." }, "skipped": { "type": "number", "description": "Source records left unchanged or not imported." } }, "required": [ "scanned", "created", "updated", "skipped" ], "additionalProperties": false, "description": "Sales opportunity records included in the import." }, "notes": { "type": "object", "properties": { "scanned": { "type": "number", "description": "Source records examined by the import." }, "created": { "type": "number", "description": "Records newly created by the import, or whether this reusable item was newly created." }, "updated": { "type": "number", "description": "Existing records updated by the import." }, "skipped": { "type": "number", "description": "Source records left unchanged or not imported." } }, "required": [ "scanned", "created", "updated", "skipped" ], "additionalProperties": false, "description": "Note records included in the import." }, "tasks": { "type": "object", "properties": { "scanned": { "type": "number", "description": "Source records examined by the import." }, "created": { "type": "number", "description": "Records newly created by the import, or whether this reusable item was newly created." }, "updated": { "type": "number", "description": "Existing records updated by the import." }, "skipped": { "type": "number", "description": "Source records left unchanged or not imported." } }, "required": [ "scanned", "created", "updated", "skipped" ], "additionalProperties": false, "description": "Task records included in the import." } }, "required": [], "additionalProperties": false, "description": "Per-object counts for the import." }, "limitations": { "type": "array", "items": { "type": "object", "properties": { "key": { "type": "string", "description": "Stable key identifying this option within its collection; distinct from its display label." }, "reason": { "type": "string", "enum": [ "missing_scope", "no_equivalent", "degraded", "not_available" ], "description": "Explanation of why this outcome occurred." }, "detail": { "type": "string", "description": "Additional explanation of the reported result." }, "count": { "type": "number", "description": "Number of matching items represented by this result." } }, "required": [ "key", "reason" ], "additionalProperties": false }, "description": "Known exclusions or incomplete coverage in this import run." }, "portal": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier. Use the value returned by a create or list operation." }, "domain": { "type": "string", "description": "Website hostname, without a scheme or path." }, "currency": { "type": "string", "description": "Three-letter currency code, such as NOK, SEK or EUR." } }, "required": [], "additionalProperties": false, "description": "Provider account or portal identifier used by this connection." } }, "required": [ "counts", "limitations" ], "additionalProperties": false }, "started_at": { "type": "number", "description": "Time this work started, in Unix milliseconds." }, "completed_at": { "type": [ "number", "null" ], "description": "Time this work completed, in Unix milliseconds." } }, "required": [ "job_id", "status", "progress_percent", "report", "started_at" ], "additionalProperties": false, "examples": [ { "job_id": "e_example", "status": "completed", "progress_percent": 1, "report": { "counts": {}, "limitations": [] }, "started_at": 1794301200000 } ] } ``` --- # Get CRM import status Read the connected CRM account, supported objects and latest import report. Connect or reconnect the provider in Brigg before starting an import. Provider credentials and raw authorization settings are not returned. POST https://api.brigg.app/v1/operations/customers.GetCrmImportStatus ## Access & visibility Allow `customers.GetCrmImportStatus` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/permissions) ## Request No parameters. Send an empty JSON object (`{}`). ## Import from a connected CRM Use [Get CRM import status](/developers/reference/customers/GetCrmImportStatus) to inspect the HubSpot connection, supported objects and the most recent run. [Preview CRM import](/developers/reference/customers/PreviewCrmImport) reads a sample without writing contacts. A missing provider scope requires reconnecting in Brigg; an API grant cannot supply missing provider consent. Start the connected-CRM import in Brigg. [Get CRM import run](/developers/reference/customers/GetCrmImportRun) reads its progress and detailed report. Review created, updated, skipped and not-imported counts; a finished run does not mean every source object was supported. To import through the public API, use [Start record import](/developers/reference/integrations/StartRecordImport) with a file and permanent external references. That workflow keeps the credential’s approved operation and resource permissions throughout background processing. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `provider` | string | Yes | External service provider used by this connection. | | `connection` | [object](#response-connection) | Yes | Connected provider account and its available import capabilities. | | `optional` | array of string | Yes | Optional object types supported by this import. | | `always` | array of string | Yes | Whether the action applies regardless of the existing cached result. | | `not_imported` | array of [GetCrmImportStatusNotImported](#getcrmimportstatusnotimported-response-not-imported) | Yes | Object types or records this integration does not import. | | `latest_job` | [object](#response-latest-job) or null | Yes | Latest run. | ### response.connection | Field | Type | Required | Description | | --- | --- | --- | --- | | `connected` | boolean | Yes | Whether the CRM provider connection is active. | | `account_domain` | string or null | No | Portal domain. | | `currency` | string or null | No | Portal currency. | | `status` | string or null | No | Current state reported for this item. Treat values as extensible unless an enum is declared. | | `connected_at` | number | No | Recorded event time in Unix milliseconds. | ### GetCrmImportStatusNotImported · response.not_imported[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `key` | string | Yes | Stable key identifying this option within its collection; distinct from its display label. | | `reason` | string | Yes | Explanation of why this outcome occurred. Allowed: `"missing_scope"`, `"no_equivalent"`, `"degraded"`, `"not_available"`. | | `detail` | string | No | Additional explanation of the reported result. | | `count` | number | No | Number of matching items represented by this result. | ### response.latest_job | Field | Type | Required | Description | | --- | --- | --- | --- | | `job_id` | string | Yes | Run identifier. | | `status` | string | Yes | queued \| running \| done \| failed | | `progress_percent` | number | Yes | Progress pct. | | `phase` | string | No | Current phase of the background import or preparation job. | | `report` | [CrmImportReport](#crmimportreport-response-latest-job-report) | Yes | Import counts, exclusions and limitations from the run. | | `started_at` | number | Yes | Time this work started, in Unix milliseconds. | | `completed_at` | number or null | No | Time this work completed, in Unix milliseconds. | ### CrmImportReport · response.latest_job.report | Field | Type | Required | Description | | --- | --- | --- | --- | | `counts` | [object](#response-latest-job-report-counts) | Yes | Per-object counts for the import. | | `limitations` | array of [object](#response-latest-job-report-limitations) | Yes | Known exclusions or incomplete coverage in this import run. | | `portal` | [object](#response-latest-job-report-portal) | No | Provider account or portal identifier used by this connection. | ### response.latest_job.report.counts | Field | Type | Required | Description | | --- | --- | --- | --- | | `companies` | [object](#response-latest-job-report-counts-companies) | No | Company records included in the import or search. | | `contacts` | [object](#response-latest-job-report-counts-contacts) | No | Contact records included in the import. | | `deals` | [object](#response-latest-job-report-counts-deals) | No | Sales opportunity records included in the import. | | `notes` | [object](#response-latest-job-report-counts-notes) | No | Note records included in the import. | | `tasks` | [object](#response-latest-job-report-counts-tasks) | No | Task records included in the import. | ### response.latest_job.report.counts.companies | Field | Type | Required | Description | | --- | --- | --- | --- | | `scanned` | number | Yes | Source records examined by the import. | | `created` | number | Yes | Records newly created by the import, or whether this reusable item was newly created. | | `updated` | number | Yes | Existing records updated by the import. | | `skipped` | number | Yes | Source records left unchanged or not imported. | ### response.latest_job.report.counts.contacts | Field | Type | Required | Description | | --- | --- | --- | --- | | `scanned` | number | Yes | Source records examined by the import. | | `created` | number | Yes | Records newly created by the import, or whether this reusable item was newly created. | | `updated` | number | Yes | Existing records updated by the import. | | `skipped` | number | Yes | Source records left unchanged or not imported. | ### response.latest_job.report.counts.deals | Field | Type | Required | Description | | --- | --- | --- | --- | | `scanned` | number | Yes | Source records examined by the import. | | `created` | number | Yes | Records newly created by the import, or whether this reusable item was newly created. | | `updated` | number | Yes | Existing records updated by the import. | | `skipped` | number | Yes | Source records left unchanged or not imported. | ### response.latest_job.report.counts.notes | Field | Type | Required | Description | | --- | --- | --- | --- | | `scanned` | number | Yes | Source records examined by the import. | | `created` | number | Yes | Records newly created by the import, or whether this reusable item was newly created. | | `updated` | number | Yes | Existing records updated by the import. | | `skipped` | number | Yes | Source records left unchanged or not imported. | ### response.latest_job.report.counts.tasks | Field | Type | Required | Description | | --- | --- | --- | --- | | `scanned` | number | Yes | Source records examined by the import. | | `created` | number | Yes | Records newly created by the import, or whether this reusable item was newly created. | | `updated` | number | Yes | Existing records updated by the import. | | `skipped` | number | Yes | Source records left unchanged or not imported. | ### response.latest_job.report.limitations[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `key` | string | Yes | Stable key identifying this option within its collection; distinct from its display label. | | `reason` | string | Yes | Explanation of why this outcome occurred. Allowed: `"missing_scope"`, `"no_equivalent"`, `"degraded"`, `"not_available"`. | | `detail` | string | No | Additional explanation of the reported result. | | `count` | number | No | Number of matching items represented by this result. | ### response.latest_job.report.portal | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Unique identifier. Use the value returned by a create or list operation. | | `domain` | string | No | Website hostname, without a scheme or path. | | `currency` | string | No | Three-letter currency code, such as NOK, SEK or EUR. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [Preview CRM import](/developers/reference/customers/PreviewCrmImport) - [Get CRM import run](/developers/reference/customers/GetCrmImportRun) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.GetCrmImportStatus' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{}' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.GetCrmImportStatus", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/customers.GetCrmImportStatus", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "provider": "hubspot", "connection": { "connected": false }, "optional": [ "deals", "tasks" ], "always": [ "companies", "contacts", "notes" ], "not_imported": [], "latest_job": null } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": {}, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "provider": { "type": "string", "description": "External service provider used by this connection." }, "connection": { "type": "object", "properties": { "connected": { "type": "boolean", "description": "Whether the CRM provider connection is active." }, "account_domain": { "type": [ "string", "null" ], "description": "Portal domain." }, "currency": { "type": [ "string", "null" ], "description": "Portal currency." }, "status": { "type": [ "string", "null" ], "description": "Current state reported for this item. Treat values as extensible unless an enum is declared." }, "connected_at": { "type": "number", "description": "Recorded event time in Unix milliseconds." } }, "required": [ "connected" ], "additionalProperties": false, "description": "Connected provider account and its available import capabilities." }, "optional": { "type": "array", "items": { "type": "string" }, "description": "Optional object types supported by this import." }, "always": { "type": "array", "items": { "type": "string" }, "description": "Whether the action applies regardless of the existing cached result." }, "not_imported": { "type": "array", "items": { "title": "GetCrmImportStatusNotImported", "type": "object", "properties": { "key": { "type": "string", "description": "Stable key identifying this option within its collection; distinct from its display label." }, "reason": { "type": "string", "enum": [ "missing_scope", "no_equivalent", "degraded", "not_available" ], "description": "Explanation of why this outcome occurred." }, "detail": { "type": "string", "description": "Additional explanation of the reported result." }, "count": { "type": "number", "description": "Number of matching items represented by this result." } }, "required": [ "key", "reason" ], "additionalProperties": false }, "description": "Object types or records this integration does not import." }, "latest_job": { "type": [ "object", "null" ], "properties": { "job_id": { "type": "string", "description": "Run identifier." }, "status": { "type": "string", "description": "queued | running | done | failed" }, "progress_percent": { "type": "number", "description": "Progress pct." }, "phase": { "type": "string", "description": "Current phase of the background import or preparation job." }, "report": { "description": "Import counts, exclusions and limitations from the run.", "title": "CrmImportReport", "type": "object", "properties": { "counts": { "type": "object", "properties": { "companies": { "type": "object", "properties": { "scanned": { "type": "number", "description": "Source records examined by the import." }, "created": { "type": "number", "description": "Records newly created by the import, or whether this reusable item was newly created." }, "updated": { "type": "number", "description": "Existing records updated by the import." }, "skipped": { "type": "number", "description": "Source records left unchanged or not imported." } }, "required": [ "scanned", "created", "updated", "skipped" ], "additionalProperties": false, "description": "Company records included in the import or search." }, "contacts": { "type": "object", "properties": { "scanned": { "type": "number", "description": "Source records examined by the import." }, "created": { "type": "number", "description": "Records newly created by the import, or whether this reusable item was newly created." }, "updated": { "type": "number", "description": "Existing records updated by the import." }, "skipped": { "type": "number", "description": "Source records left unchanged or not imported." } }, "required": [ "scanned", "created", "updated", "skipped" ], "additionalProperties": false, "description": "Contact records included in the import." }, "deals": { "type": "object", "properties": { "scanned": { "type": "number", "description": "Source records examined by the import." }, "created": { "type": "number", "description": "Records newly created by the import, or whether this reusable item was newly created." }, "updated": { "type": "number", "description": "Existing records updated by the import." }, "skipped": { "type": "number", "description": "Source records left unchanged or not imported." } }, "required": [ "scanned", "created", "updated", "skipped" ], "additionalProperties": false, "description": "Sales opportunity records included in the import." }, "notes": { "type": "object", "properties": { "scanned": { "type": "number", "description": "Source records examined by the import." }, "created": { "type": "number", "description": "Records newly created by the import, or whether this reusable item was newly created." }, "updated": { "type": "number", "description": "Existing records updated by the import." }, "skipped": { "type": "number", "description": "Source records left unchanged or not imported." } }, "required": [ "scanned", "created", "updated", "skipped" ], "additionalProperties": false, "description": "Note records included in the import." }, "tasks": { "type": "object", "properties": { "scanned": { "type": "number", "description": "Source records examined by the import." }, "created": { "type": "number", "description": "Records newly created by the import, or whether this reusable item was newly created." }, "updated": { "type": "number", "description": "Existing records updated by the import." }, "skipped": { "type": "number", "description": "Source records left unchanged or not imported." } }, "required": [ "scanned", "created", "updated", "skipped" ], "additionalProperties": false, "description": "Task records included in the import." } }, "required": [], "additionalProperties": false, "description": "Per-object counts for the import." }, "limitations": { "type": "array", "items": { "type": "object", "properties": { "key": { "type": "string", "description": "Stable key identifying this option within its collection; distinct from its display label." }, "reason": { "type": "string", "enum": [ "missing_scope", "no_equivalent", "degraded", "not_available" ], "description": "Explanation of why this outcome occurred." }, "detail": { "type": "string", "description": "Additional explanation of the reported result." }, "count": { "type": "number", "description": "Number of matching items represented by this result." } }, "required": [ "key", "reason" ], "additionalProperties": false }, "description": "Known exclusions or incomplete coverage in this import run." }, "portal": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier. Use the value returned by a create or list operation." }, "domain": { "type": "string", "description": "Website hostname, without a scheme or path." }, "currency": { "type": "string", "description": "Three-letter currency code, such as NOK, SEK or EUR." } }, "required": [], "additionalProperties": false, "description": "Provider account or portal identifier used by this connection." } }, "required": [ "counts", "limitations" ], "additionalProperties": false }, "started_at": { "type": "number", "description": "Time this work started, in Unix milliseconds." }, "completed_at": { "type": [ "number", "null" ], "description": "Time this work completed, in Unix milliseconds." } }, "required": [ "job_id", "status", "progress_percent", "report", "started_at" ], "additionalProperties": false, "description": "Latest run." } }, "required": [ "provider", "connection", "optional", "always", "not_imported", "latest_job" ], "additionalProperties": false, "examples": [ { "provider": "hubspot", "connection": { "connected": false }, "optional": [ "deals", "tasks" ], "always": [ "companies", "contacts", "notes" ], "not_imported": [], "latest_job": null } ] } ``` --- # Preview contact import Prepare contacts from an uploaded CSV, TSV or vCard without saving records or making an AI call. Supply zero-based column mappings for a table. Review each row, check existing contacts, then use customers.CreatePerson or customers.UpdatePerson to import them with the usual permissions and retry guarantees. Names, email addresses, phone numbers, job titles and LinkedIn URLs are supported. POST https://api.brigg.app/v1/operations/customers.PreviewContactImport ## Access & visibility Allow `customers.PreviewContactImport` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `file_id` | string | Yes | Use a file_id returned by this listing or by CompleteUpload. It is not an upload ID, storage path or filename. [documents.ListDocuments](/developers/reference/documents/ListDocuments). At least 1 character. | | `has_header` | boolean | No | Whether the uploaded table's first row contains column headings. Default: `true`. | | `mapping` | [object](#request-mapping) | No | Mapping from supported Person fields to zero-based table column indexes. | | `limit` | integer | No | Maximum number of results to return in this page. Continue with next_cursor when returned. Default: `50`. Range: 1 to 100. | | `cursor` | string | No | Copy next_cursor from the preceding response. Keep the same filters, sort and credential. | ### request.mapping | Field | Type | Required | Description | | --- | --- | --- | --- | | `display_name` | integer | No | Full name shown for the contact. Minimum: 0. | | `email` | integer | No | Email address. Minimum: 0. | | `phone` | integer | No | Phone number including its country calling code. Minimum: 0. | | `title` | integer | No | Display title. Minimum: 0. | | `linkedin_url` | integer | No | Public LinkedIn profile URL for the person or company. Minimum: 0. | ## Response Returns **200 OK** with a JSON body. An empty `items` array means this page contains no matching visible results. Follow `next_cursor` when present. | Field | Type | Required | Description | | --- | --- | --- | --- | | `file_id` | string | Yes | File identifier. | | `row_count` | integer | Yes | Number of source rows detected in the uploaded file. | | `duplicate_count` | integer | Yes | Number of source rows classified as duplicates. | | `invalid_count` | integer | Yes | Number of source rows that did not pass the contact-field checks. | | `items` | array of [Contact import row](#contact-import-row-response-items) | Yes | Parsed rows from the uploaded file, with validation and duplicate results. Pass next_cursor as cursor to continue when a next cursor is returned. | | `next_cursor` | string or null | Yes | Pass this value as cursor to continue with the same filters, sort and credential. Null when there are no more results. | | `has_more` | boolean | Yes | Whether another page of results is available. | ### Contact import row · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `row` | integer | Yes | One-based row number in the source file. | | `status` | string | Yes | Preparation result for this row. Review invalid and duplicate rows before importing. Allowed: `"ready"`, `"duplicate"`, `"invalid"`. | | `data` | [object](#response-items-data) | No | Contact fields parsed using the supplied column mapping. | | `error` | string | No | Explanation of a row validation failure, when present. | ### response.items[].data | Field | Type | Required | Description | | --- | --- | --- | --- | | `display_name` | string | No | Full name shown for the contact. | | `email` | string | No | Email address. | | `phone` | string | No | Phone number including its country calling code. | | `title` | string | No | Display title. | | `linkedin_url` | string | No | Public LinkedIn profile URL for the person or company. | ## Pagination Pass `next_cursor` as `cursor` on the next request, keeping the same query and acting identity. Stop when `next_cursor` is null. Treat the cursor as opaque; never construct or edit it. ```typescript const query = { "file_id": "f_contacts", "has_header": true, "mapping": { "display_name": 0, "email": 1, "title": 2 }, "limit": 50 }; let cursor; do { const response = await fetch("https://api.brigg.app/v1/operations/customers.PreviewContactImport", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ ...query, ...(cursor ? { cursor } : {}) }), }); const page = await response.json(); if (!response.ok) throw new Error(`${response.status}: ${page.message}`); for (const item of page.items) { console.log(item); // Process or upsert each result. } cursor = page.next_cursor; } while (cursor); ``` ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | | 422 | `text_file_required` | Upload a text file containing CSV, TSV or vCard data. | | 422 | `invalid_text_encoding` | Upload UTF-8 text. | | 413 | `source_too_large` | Contact preparation supports the existing 4,000,000-character text-file limit; no rows are truncated. | ## Next steps - [List documents](/developers/reference/documents/ListDocuments) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.PreviewContactImport' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "file_id": "f_contacts", "has_header": true, "mapping": { "display_name": 0, "email": 1, "title": 2 }, "limit": 50 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.PreviewContactImport", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "file_id": "f_contacts", "has_header": true, "mapping": { "display_name": 0, "email": 1, "title": 2 }, "limit": 50 }), }); 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 payload = { "file_id": "f_contacts", "has_header": True, "mapping": { "display_name": 0, "email": 1, "title": 2 }, "limit": 50 } request = Request( "https://api.brigg.app/v1/operations/customers.PreviewContactImport", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "file_id": "f_contacts", "row_count": 1, "duplicate_count": 0, "invalid_count": 0, "items": [ { "row": 1, "status": "ready", "data": { "display_name": "Alex Morgan", "email": "alex@example.com", "title": "Operations manager" } } ], "has_more": false, "next_cursor": null } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "file_id": { "type": "string", "minLength": 1, "description": "Use a file_id returned by this listing or by CompleteUpload. It is not an upload ID, storage path or filename. [documents.ListDocuments](/developers/reference/documents/ListDocuments)." }, "has_header": { "type": "boolean", "default": true, "description": "Whether the uploaded table's first row contains column headings." }, "mapping": { "type": "object", "properties": { "display_name": { "type": "integer", "minimum": 0, "description": "Full name shown for the contact." }, "email": { "type": "integer", "minimum": 0, "description": "Email address." }, "phone": { "type": "integer", "minimum": 0, "description": "Phone number including its country calling code." }, "title": { "type": "integer", "minimum": 0, "description": "Display title." }, "linkedin_url": { "type": "integer", "minimum": 0, "description": "Public LinkedIn profile URL for the person or company." } }, "additionalProperties": false, "description": "Mapping from supported Person fields to zero-based table column indexes." }, "limit": { "type": "integer", "minimum": 1, "maximum": 100, "default": 50, "description": "Maximum number of results to return in this page. Continue with next_cursor when returned." }, "cursor": { "type": "string", "description": "Copy next_cursor from the preceding response. Keep the same filters, sort and credential." } }, "required": [ "file_id" ], "additionalProperties": false, "examples": [ { "file_id": "f_contacts", "has_header": true, "mapping": { "display_name": 0, "email": 1, "title": 2 }, "limit": 50 } ] } ``` ```json-schema-response { "type": "object", "properties": { "file_id": { "type": "string", "description": "File identifier." }, "row_count": { "type": "integer", "description": "Number of source rows detected in the uploaded file." }, "duplicate_count": { "type": "integer", "description": "Number of source rows classified as duplicates." }, "invalid_count": { "type": "integer", "description": "Number of source rows that did not pass the contact-field checks." }, "items": { "type": "array", "items": { "type": "object", "properties": { "row": { "type": "integer", "description": "One-based row number in the source file." }, "status": { "type": "string", "enum": [ "ready", "duplicate", "invalid" ], "description": "Preparation result for this row. Review invalid and duplicate rows before importing." }, "data": { "type": "object", "properties": { "display_name": { "type": "string", "description": "Full name shown for the contact." }, "email": { "type": "string", "description": "Email address." }, "phone": { "type": "string", "description": "Phone number including its country calling code." }, "title": { "type": "string", "description": "Display title." }, "linkedin_url": { "type": "string", "description": "Public LinkedIn profile URL for the person or company." } }, "additionalProperties": false, "description": "Contact fields parsed using the supplied column mapping." }, "error": { "type": "string", "description": "Explanation of a row validation failure, when present." } }, "required": [ "row", "status" ], "additionalProperties": false, "title": "Contact import row" }, "description": "Parsed rows from the uploaded file, with validation and duplicate results. Pass next_cursor as cursor to continue when a next cursor is returned." }, "next_cursor": { "type": [ "string", "null" ], "description": "Pass this value as cursor to continue with the same filters, sort and credential. Null when there are no more results." }, "has_more": { "type": "boolean", "description": "Whether another page of results is available." } }, "required": [ "file_id", "row_count", "duplicate_count", "invalid_count", "items", "next_cursor", "has_more" ], "additionalProperties": false, "examples": [ { "file_id": "f_contacts", "row_count": 1, "duplicate_count": 0, "invalid_count": 0, "items": [ { "row": 1, "status": "ready", "data": { "display_name": "Alex Morgan", "email": "alex@example.com", "title": "Operations manager" } } ], "has_more": false, "next_cursor": null } ] } ``` --- # Preview CRM import Preview counts and sample labels for the connected HubSpot CRM before importing. This reads the available object types without creating or updating Brigg records. POST https://api.brigg.app/v1/operations/customers.PreviewCrmImport ## Access & visibility Allow `customers.PreviewCrmImport` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/permissions) ## Request No parameters. Send an empty JSON object (`{}`). ## Import from a connected CRM Use [Get CRM import status](/developers/reference/customers/GetCrmImportStatus) to inspect the HubSpot connection, supported objects and the most recent run. [Preview CRM import](/developers/reference/customers/PreviewCrmImport) reads a sample without writing contacts. A missing provider scope requires reconnecting in Brigg; an API grant cannot supply missing provider consent. Start the connected-CRM import in Brigg. [Get CRM import run](/developers/reference/customers/GetCrmImportRun) reads its progress and detailed report. Review created, updated, skipped and not-imported counts; a finished run does not mean every source object was supported. To import through the public API, use [Start record import](/developers/reference/integrations/StartRecordImport) with a file and permanent external references. That workflow keeps the credential’s approved operation and resource permissions throughout background processing. ## Response Returns **200 OK** with a JSON body. This operation has no continuation cursor. An empty `items` array means no matching visible results were returned. A preview can partially succeed. Check every row's missing_scope before selecting categories. A zero count without missing_scope may mean no records or a per-category provider read failure; the preview is advisory, not proof that the CRM is empty. Only open tasks are candidates. No Brigg records are changed. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [CRM import preview](#crm-import-preview-response-items) | Yes | Source records available for preview from the connected CRM. This does not import them. This operation has no cursor pagination. | ### CRM import preview · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `object` | string | Yes | HubSpot object category: companies, contacts, deals, notes or tasks. Choose the categories to import later when starting the run. | | `total` | number | Yes | Estimated importable count for this category. Known skipped records in the fetched preview page are deducted, so larger sets may still overestimate; use the completed run report for actual counts. Zero can also accompany a per-category provider failure. | | `samples` | array of string | Yes | Up to three human-readable labels from candidate records, not record IDs or full objects. These help recognize the source data, not address individual import items. | | `missing_scope` | string | No | When present, this category could not be previewed because the connection lacks this provider scope. Its total is zero and samples is empty; this does not prove the source category has no data. Other categories can still be available. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `not_connected` | Connect the workspace HubSpot account in Brigg first. | | 409 | `auth_expired` | Renew the HubSpot connection before previewing again. | ## Next steps - [Get CRM import status](/developers/reference/customers/GetCrmImportStatus) - [Get CRM import run](/developers/reference/customers/GetCrmImportRun) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Some categories need more provider access Use available rows to plan the import. Reconnect with the needed provider scopes before selecting a blocked category. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.PreviewCrmImport' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{}' ``` #### TypeScript ```typescript 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/customers.PreviewCrmImport", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({}), }); 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 = {} request = Request( "https://api.brigg.app/v1/operations/customers.PreviewCrmImport", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "items": [ { "object": "companies", "total": 42, "samples": [ "Northstar Ltd", "Harbor Studio" ] }, { "object": "contacts", "total": 86, "samples": [ "Alex Morgan", "Sam Lee" ] }, { "object": "deals", "total": 0, "samples": [], "missing_scope": "crm.objects.deals.read" }, { "object": "notes", "total": 12, "samples": [ "Pilot planning notes" ] }, { "object": "tasks", "total": 8, "samples": [ "Confirm kickoff date" ] } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": {}, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "object": { "type": "string", "description": "HubSpot object category: companies, contacts, deals, notes or tasks. Choose the categories to import later when starting the run.", "examples": [ "companies" ] }, "total": { "type": "number", "description": "Estimated importable count for this category. Known skipped records in the fetched preview page are deducted, so larger sets may still overestimate; use the completed run report for actual counts. Zero can also accompany a per-category provider failure.", "examples": [ 12 ] }, "samples": { "type": "array", "items": { "type": "string" }, "description": "Up to three human-readable labels from candidate records, not record IDs or full objects. These help recognize the source data, not address individual import items.", "examples": [ [ "Northwind Consulting AS" ] ] }, "missing_scope": { "type": "string", "description": "When present, this category could not be previewed because the connection lacks this provider scope. Its total is zero and samples is empty; this does not prove the source category has no data. Other categories can still be available.", "examples": [ "crm.objects.companies.read" ] } }, "required": [ "object", "total", "samples" ], "additionalProperties": false, "title": "CRM import preview" }, "description": "Source records available for preview from the connected CRM. This does not import them. This operation has no cursor pagination." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "object": "companies", "total": 42, "samples": [ "Northstar Ltd", "Harbor Studio" ] }, { "object": "contacts", "total": 86, "samples": [ "Alex Morgan", "Sam Lee" ] }, { "object": "deals", "total": 0, "samples": [], "missing_scope": "crm.objects.deals.read" }, { "object": "notes", "total": 12, "samples": [ "Pilot planning notes" ] }, { "object": "tasks", "total": 8, "samples": [ "Confirm kickoff date" ] } ] } ] } ``` --- # Get note Read a note by ID. Returns item: null when no visible record matches. POST https://api.brigg.app/v1/operations/customers.GetNote ## Access & visibility Allow `customers.GetNote` on your API key. Resource read permissions: `core:Note`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:Note` record. Find it with [customers.ListNotes](/developers/reference/customers/ListNotes). Use the record's top-level `id`, not a business field or account ID. | ## Response Returns **200 OK** with a JSON body. `item: null` means there is no matching record visible to this caller. It does not reveal whether an inaccessible record exists. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [NoteRecord](#noterecord-response-item) or null | Yes | null when no such record | ### NoteRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Note record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Note](#note-response-item-data) | Yes | The record's fields. | ### Note · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `body` | string | Yes | Customer activity note content, which may contain Markdown. Preserve the text and render it safely; this is not HTML. | | `occurred_at` | string | No | Date of the activity described by the note, in YYYY-MM-DD format. Creation time is recorded separately. | | `parent_type` | string | No | CRM parent type: core:Company, core:Person or core:Deal. Pair with parent_id. These resource identifiers differ from public operation namespaces. | | `parent_id` | string | No | Record ID within parent_type. The type and ID must identify the same parent. | | `author_ref` | string | No | Person record representing the note's author, not the author's account ID. Brigg supplies the acting member's Person reference on creation when omitted. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [List notes](/developers/reference/customers/ListNotes) - [Create note](/developers/reference/customers/CreateNote) - [Upsert note](/developers/reference/customers/UpsertNote) - [Update note](/developers/reference/customers/UpdateNote) - [Delete note](/developers/reference/customers/DeleteNote) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.GetNote' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "e_note_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.GetNote", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "id": "e_note_example" }), }); 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 payload = { "id": "e_note_example" } request = Request( "https://api.brigg.app/v1/operations/customers.GetNote", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "item": { "id": "e_note_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "body": "Alex confirmed that the pilot will start on 19 October.", "occurred_at": "2026-10-06", "parent_type": "core:Company", "parent_id": "e_company_northstar" } } } ``` ### No visible record A missing or inaccessible record returns item: null. Do not treat this as proof that a record exists for another member. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.GetNote' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "e_note_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.GetNote", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "id": "e_note_example" }), }); 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 payload = { "id": "e_note_example" } request = Request( "https://api.brigg.app/v1/operations/customers.GetNote", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "item": null } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:Note` record. Find it with [customers.ListNotes](/developers/reference/customers/ListNotes). Use the record's top-level `id`, not a business field or account ID." } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_note_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": [ "object", "null" ], "properties": { "id": { "type": "string", "description": "Stable core:Note record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "body": { "type": "string", "description": "Customer activity note content, which may contain Markdown. Preserve the text and render it safely; this is not HTML." }, "occurred_at": { "type": "string", "description": "Date of the activity described by the note, in YYYY-MM-DD format. Creation time is recorded separately." }, "parent_type": { "type": "string", "description": "CRM parent type: core:Company, core:Person or core:Deal. Pair with parent_id. These resource identifiers differ from public operation namespaces." }, "parent_id": { "type": "string", "description": "Record ID within parent_type. The type and ID must identify the same parent." }, "author_ref": { "type": "string", "description": "Person record representing the note's author, not the author's account ID. Brigg supplies the acting member's Person reference on creation when omitted." } }, "required": [ "body" ], "additionalProperties": false, "description": "The record's fields.", "title": "Note" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "null when no such record", "title": "NoteRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_note_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "body": "Alex confirmed that the pilot will start on 19 October.", "occurred_at": "2026-10-06", "parent_type": "core:Company", "parent_id": "e_company_northstar" } } } ] } ``` --- # List notes List notes visible to the credential, with filtering, sorting and cursor pagination. POST https://api.brigg.app/v1/operations/customers.ListNotes ## Access & visibility Allow `customers.ListNotes` on your API key. Resource read permissions: `core:Note`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `filters` | array of [object](#request-filters) | No | Conditions the row must ALL satisfy. | | `sort` | [object](#request-sort) | No | Sort order for the results. Defaults to updated_at descending, with id as a tie-breaker. | | `limit` | integer | No | Maximum number of results to return in this page. Continue with next_cursor when returned. Default: `100`. Minimum: 1. | | `cursor` | string | No | The `next_cursor` of the previous page. | ### request.filters[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | `data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private. Allowed: `"id"`, `"created_at"`, `"updated_at"`, `"created_by"`, `"private"`, `"data.body"`, `"data.occurred_at"`, `"data.parent_type"`, `"data.parent_id"`, `"data.author_ref"`. | | `op` | string | Yes | Comparison operator. Use in with an array, or omit value for is_empty and is_not_empty. Allowed: `"eq"`, `"neq"`, `"contains"`, `"starts_with"`, `"gt"`, `"gte"`, `"lt"`, `"lte"`, `"in"`, `"has"`, `"is_empty"`, `"is_not_empty"`. | | `value` | JSON value | No | The comparison value; an array for `in`; omitted for is_empty / is_not_empty. | ### request.sort | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | `data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private. Allowed: `"id"`, `"created_at"`, `"updated_at"`, `"created_by"`, `"private"`, `"data.body"`, `"data.occurred_at"`, `"data.parent_type"`, `"data.parent_id"`, `"data.author_ref"`. | | `direction` | string | No | Sort direction: asc for ascending or desc for descending. Allowed: `"asc"`, `"desc"`. | ## Filtering and sorting All conditions are combined with **AND**. Address business fields as `data.`, and record metadata as `id`, `created_at`, `updated_at`, `created_by` or `private`. A field path names one field; it does not traverse nested objects. | Operator | Meaning | Value | | --- | --- | --- | | `eq` | Equal to a scalar | String, number, boolean or null | | `neq` | Not equal; missing values also match | String, number, boolean or null | | `contains` | Case-insensitive text contains | String; % and _ are literal characters | | `starts_with` | Case-insensitive text prefix | String | | `gt`, `gte` | Greater than / at least | Number or string appropriate to the field | | `lt`, `lte` | Less than / at most | Number or string appropriate to the field | | `in` | Equal to any supplied scalar | Nonempty array of strings, numbers, booleans or null | | `has` | Array contains a string | One string; does not match properties inside array objects | | `is_empty` | Missing, null, empty string or empty array | Omit value | | `is_not_empty` | Has a nonempty value | Omit value | Match the stored field's type. Numeric business timestamps take Unix milliseconds; date-only business fields take `YYYY-MM-DD`. The record metadata fields `created_at` and `updated_at` also accept ISO timestamps for ordered comparisons. Sorting defaults to `updated_at` descending. If you supply `sort.field` without `sort.direction`, direction is `desc`. The record ID breaks ties; missing values sort last. ## Response Returns **200 OK** with a JSON body. An empty `items` array means this page contains no matching visible results. Follow `next_cursor` when present. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [NoteRecord](#noterecord-response-items) | Yes | Records visible under the credential's grants and the selected data scope, matching the requested filters. Pass next_cursor as cursor to continue when a next cursor is returned. | | `next_cursor` | string | No | Pass this value as cursor to continue with the same filters, sort and credential. Omitted when there are no more results. | ### NoteRecord · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Note record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Note](#note-response-items-data) | Yes | The record's fields. | ### Note · response.items[].data | Field | Type | Required | Description | | --- | --- | --- | --- | | `body` | string | Yes | Customer activity note content, which may contain Markdown. Preserve the text and render it safely; this is not HTML. | | `occurred_at` | string | No | Date of the activity described by the note, in YYYY-MM-DD format. Creation time is recorded separately. | | `parent_type` | string | No | CRM parent type: core:Company, core:Person or core:Deal. Pair with parent_id. These resource identifiers differ from public operation namespaces. | | `parent_id` | string | No | Record ID within parent_type. The type and ID must identify the same parent. | | `author_ref` | string | No | Person record representing the note's author, not the author's account ID. Brigg supplies the acting member's Person reference on creation when omitted. | ## Pagination Pass `next_cursor` from the response as `cursor` on the next request. Keep the same filters, sort and acting identity. Stop when `next_cursor` is absent; do not infer completion from the number of items. The default page size is **100**; `limit` must be a positive integer. **Pagination is a live view, not a snapshot.** Changes between pages can move records across page boundaries. Upsert by record ID rather than appending blindly. For recurring synchronization, use an overlapping update window and deduplicate records. Periodically reconcile IDs to detect deletions. [Resource webhooks](/developers/webhooks) can supplement synchronization for eligible workspace-shared records only: they do not export private or project-scoped records. Personal data still needs polling and reconciliation. ```typescript const query = { "limit": 10 }; let cursor; do { const response = await fetch("https://api.brigg.app/v1/operations/customers.ListNotes", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ ...query, ...(cursor ? { cursor } : {}) }), }); const page = await response.json(); if (!response.ok) throw new Error(`${response.status}: ${page.message}`); for (const item of page.items) { console.log(item); // Process or upsert each result. } cursor = page.next_cursor; } while (cursor); ``` ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | | 400 | `cursor_invalid` | Restart pagination with no cursor. | | 400 | `cursor_mismatch` | Use the cursor with the original filters, sort order and credential. | ## Next steps - [Get note](/developers/reference/customers/GetNote) - [Create note](/developers/reference/customers/CreateNote) - [Upsert note](/developers/reference/customers/UpsertNote) - [Update note](/developers/reference/customers/UpdateNote) - [Delete note](/developers/reference/customers/DeleteNote) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### First page Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.ListNotes' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "limit": 10 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.ListNotes", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "limit": 10 }), }); 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 payload = { "limit": 10 } request = Request( "https://api.brigg.app/v1/operations/customers.ListNotes", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_note_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "body": "Alex confirmed that the pilot will start on 19 October.", "occurred_at": "2026-10-06", "parent_type": "core:Company", "parent_id": "e_company_northstar" } } ] } ``` ### Notes for one customer Match both the parent type and record ID. Sort the activity date separately from the note's creation time. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.ListNotes' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "limit": 50, "filters": [ { "field": "data.parent_type", "op": "eq", "value": "core:Company" }, { "field": "data.parent_id", "op": "eq", "value": "e_company_northstar" } ], "sort": { "field": "data.occurred_at", "direction": "desc" } }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.ListNotes", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "limit": 50, "filters": [ { "field": "data.parent_type", "op": "eq", "value": "core:Company" }, { "field": "data.parent_id", "op": "eq", "value": "e_company_northstar" } ], "sort": { "field": "data.occurred_at", "direction": "desc" } }), }); 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 payload = { "limit": 50, "filters": [ { "field": "data.parent_type", "op": "eq", "value": "core:Company" }, { "field": "data.parent_id", "op": "eq", "value": "e_company_northstar" } ], "sort": { "field": "data.occurred_at", "direction": "desc" } } request = Request( "https://api.brigg.app/v1/operations/customers.ListNotes", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_note_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "body": "Alex confirmed that the pilot will start on 19 October.", "occurred_at": "2026-10-06", "parent_type": "core:Company", "parent_id": "e_company_northstar" } } ] } ``` ### Records updated since a checkpoint 6 October 2026 at 00:00 UTC. Use an overlap window and upsert by ID when synchronizing. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.ListNotes' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.ListNotes", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 }), }); 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 payload = { "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 } request = Request( "https://api.brigg.app/v1/operations/customers.ListNotes", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_note_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "body": "Alex confirmed that the pilot will start on 19 October.", "occurred_at": "2026-10-06", "parent_type": "core:Company", "parent_id": "e_company_northstar" } } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "filters": { "type": "array", "items": { "type": "object", "properties": { "field": { "type": "string", "description": "`data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private.", "enum": [ "id", "created_at", "updated_at", "created_by", "private", "data.body", "data.occurred_at", "data.parent_type", "data.parent_id", "data.author_ref" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "contains", "starts_with", "gt", "gte", "lt", "lte", "in", "has", "is_empty", "is_not_empty" ], "description": "Comparison operator. Use in with an array, or omit value for is_empty and is_not_empty." }, "value": { "description": "The comparison value; an array for `in`; omitted for is_empty / is_not_empty." } }, "required": [ "field", "op" ], "additionalProperties": false }, "description": "Conditions the row must ALL satisfy." }, "sort": { "type": "object", "properties": { "field": { "type": "string", "description": "`data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private.", "enum": [ "id", "created_at", "updated_at", "created_by", "private", "data.body", "data.occurred_at", "data.parent_type", "data.parent_id", "data.author_ref" ] }, "direction": { "type": "string", "enum": [ "asc", "desc" ], "description": "Sort direction: asc for ascending or desc for descending." } }, "required": [ "field" ], "additionalProperties": false, "description": "Sort order for the results. Defaults to updated_at descending, with id as a tie-breaker." }, "limit": { "type": "integer", "minimum": 1, "default": 100, "description": "Maximum number of results to return in this page. Continue with next_cursor when returned." }, "cursor": { "type": "string", "description": "The `next_cursor` of the previous page." } }, "additionalProperties": false, "examples": [ { "limit": 10 } ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:Note record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "body": { "type": "string", "description": "Customer activity note content, which may contain Markdown. Preserve the text and render it safely; this is not HTML." }, "occurred_at": { "type": "string", "description": "Date of the activity described by the note, in YYYY-MM-DD format. Creation time is recorded separately." }, "parent_type": { "type": "string", "description": "CRM parent type: core:Company, core:Person or core:Deal. Pair with parent_id. These resource identifiers differ from public operation namespaces." }, "parent_id": { "type": "string", "description": "Record ID within parent_type. The type and ID must identify the same parent." }, "author_ref": { "type": "string", "description": "Person record representing the note's author, not the author's account ID. Brigg supplies the acting member's Person reference on creation when omitted." } }, "required": [ "body" ], "additionalProperties": false, "description": "The record's fields.", "title": "Note" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "title": "NoteRecord" }, "description": "Records visible under the credential's grants and the selected data scope, matching the requested filters. Pass next_cursor as cursor to continue when a next cursor is returned." }, "next_cursor": { "type": "string", "description": "Pass this value as cursor to continue with the same filters, sort and credential. Omitted when there are no more results." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "id": "e_note_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "body": "Alex confirmed that the pilot will start on 19 October.", "occurred_at": "2026-10-06", "parent_type": "core:Company", "parent_id": "e_company_northstar" } } ] } ] } ``` --- # Create note Create a note and return the saved record. POST https://api.brigg.app/v1/operations/customers.CreateNote ## Access & visibility Allow `customers.CreateNote` on your API key. Resource read permissions: `core:Note`. Resource write permissions: `core:Note`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `data` | [Note](#note-request-data) | Yes | The record's fields. | | `private` | boolean | No | Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance. | ### Note · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `body` | string | Yes | Customer activity note content, which may contain Markdown. Preserve the text and render it safely; this is not HTML. | | `occurred_at` | string | No | Date of the activity described by the note, in YYYY-MM-DD format. Creation time is recorded separately. | | `parent_type` | string | No | CRM parent type: core:Company, core:Person or core:Deal. Pair with parent_id. These resource identifiers differ from public operation namespaces. | | `parent_id` | string | No | Record ID within parent_type. The type and ID must identify the same parent. | | `author_ref` | string | No | Person record representing the note's author, not the author's account ID. Brigg supplies the acting member's Person reference on creation when omitted. | ## Choose ownership deliberately Omitting `private`, or setting it to false, creates a workspace-shared record. Set `private: true` to create a record owned by the approved acting member. Private records require member delegation; a workspace-only credential cannot own a personal record. The credential’s exact resource grants authorize the write; private ownership and project membership remain enforced. A create is a new record, not an upsert. Reuse the same idempotency key only for retries of that logical creation. For recurring synchronization, use the resource’s upsert operation when available: it matches a permanent external reference. Otherwise keep the returned record ID and use the corresponding update operation for subsequent changes. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [NoteRecord](#noterecord-response-item) | Yes | The requested record, including its metadata and data fields. | ### NoteRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Note record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Note](#note-response-item-data) | Yes | The record's fields. | ### Note · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `body` | string | Yes | Customer activity note content, which may contain Markdown. Preserve the text and render it safely; this is not HTML. | | `occurred_at` | string | No | Date of the activity described by the note, in YYYY-MM-DD format. Creation time is recorded separately. | | `parent_type` | string | No | CRM parent type: core:Company, core:Person or core:Deal. Pair with parent_id. These resource identifiers differ from public operation namespaces. | | `parent_id` | string | No | Record ID within parent_type. The type and ID must identify the same parent. | | `author_ref` | string | No | Person record representing the note's author, not the author's account ID. Brigg supplies the acting member's Person reference on creation when omitted. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List notes](/developers/reference/customers/ListNotes) - [Get note](/developers/reference/customers/GetNote) - [Upsert note](/developers/reference/customers/UpsertNote) - [Update note](/developers/reference/customers/UpdateNote) - [Delete note](/developers/reference/customers/DeleteNote) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.CreateNote' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "data": { "body": "Alex confirmed that the pilot will start on 19 October.", "occurred_at": "2026-10-06", "parent_type": "core:Company", "parent_id": "e_company_northstar" } }' ``` #### TypeScript ```typescript 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/customers.CreateNote", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "data": { "body": "Alex confirmed that the pilot will start on 19 October.", "occurred_at": "2026-10-06", "parent_type": "core:Company", "parent_id": "e_company_northstar" } }), }); 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 = { "data": { "body": "Alex confirmed that the pilot will start on 19 October.", "occurred_at": "2026-10-06", "parent_type": "core:Company", "parent_id": "e_company_northstar" } } request = Request( "https://api.brigg.app/v1/operations/customers.CreateNote", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_note_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "body": "Alex confirmed that the pilot will start on 19 October.", "occurred_at": "2026-10-06", "parent_type": "core:Company", "parent_id": "e_company_northstar" } } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "data": { "type": "object", "properties": { "body": { "type": "string", "description": "Customer activity note content, which may contain Markdown. Preserve the text and render it safely; this is not HTML." }, "occurred_at": { "type": "string", "description": "Date of the activity described by the note, in YYYY-MM-DD format. Creation time is recorded separately." }, "parent_type": { "type": "string", "description": "CRM parent type: core:Company, core:Person or core:Deal. Pair with parent_id. These resource identifiers differ from public operation namespaces." }, "parent_id": { "type": "string", "description": "Record ID within parent_type. The type and ID must identify the same parent." }, "author_ref": { "type": "string", "description": "Person record representing the note's author, not the author's account ID. Brigg supplies the acting member's Person reference on creation when omitted." } }, "required": [ "body" ], "additionalProperties": false, "description": "The record's fields.", "title": "Note" }, "private": { "type": "boolean", "description": "Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance." } }, "required": [ "data" ], "additionalProperties": false, "examples": [ { "data": { "body": "Alex confirmed that the pilot will start on 19 October.", "occurred_at": "2026-10-06", "parent_type": "core:Company", "parent_id": "e_company_northstar" } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:Note record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "body": { "type": "string", "description": "Customer activity note content, which may contain Markdown. Preserve the text and render it safely; this is not HTML." }, "occurred_at": { "type": "string", "description": "Date of the activity described by the note, in YYYY-MM-DD format. Creation time is recorded separately." }, "parent_type": { "type": "string", "description": "CRM parent type: core:Company, core:Person or core:Deal. Pair with parent_id. These resource identifiers differ from public operation namespaces." }, "parent_id": { "type": "string", "description": "Record ID within parent_type. The type and ID must identify the same parent." }, "author_ref": { "type": "string", "description": "Person record representing the note's author, not the author's account ID. Brigg supplies the acting member's Person reference on creation when omitted." } }, "required": [ "body" ], "additionalProperties": false, "description": "The record's fields.", "title": "Note" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "NoteRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_note_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "body": "Alex confirmed that the pilot will start on 19 October.", "occurred_at": "2026-10-06", "parent_type": "core:Company", "parent_id": "e_company_northstar" } } } ] } ``` --- # Delete note Delete a note by ID. Repeating a deletion returns already_deleted. POST https://api.brigg.app/v1/operations/customers.DeleteNote ## Access & visibility Allow `customers.DeleteNote` on your API key. Resource read permissions: `core:Note`. Resource write permissions: `core:Note`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:Note` record. Find it with [customers.ListNotes](/developers/reference/customers/ListNotes). Use the record's top-level `id`, not a business field or account ID. | | `expected` | [object](#request-expected) | No | Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {"$absent":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource. | ### request.expected | Field | Type | Required | Description | | --- | --- | --- | --- | | `body` | string or [object](#request-expected-body) | No | Commit only if the previous body value matches; use $absent to require that this field is missing. | | `occurred_at` | string or [object](#request-expected-occurred-at) | No | Commit only if the previous occurred_at value matches; use $absent to require that this field is missing. | | `parent_type` | string or [object](#request-expected-parent-type) | No | Commit only if the previous parent_type value matches; use $absent to require that this field is missing. | | `parent_id` | string or [object](#request-expected-parent-id) | No | Commit only if the previous parent_id value matches; use $absent to require that this field is missing. | | `author_ref` | string or [object](#request-expected-author-ref) | No | Commit only if the previous author_ref value matches; use $absent to require that this field is missing. | ### request.expected.body | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.occurred_at | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.parent_type | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.parent_id | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.author_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ## Deletion and retries A successful response reports whether this call removed the record or it was already absent. Check `cascaded` for dependent record IDs returned by the operation. Retrying the same action uses the original idempotency key. A successful deletion is not an archive you can restore through this operation. To avoid deleting a record someone has changed, read it first and put the relevant prior business values in `expected`. Keys are relative to `data`, not prefixed with `data.`. Use {"$absent": true} to require a missing field. A mismatch returns 409 conflict; read again and decide whether deletion is still appropriate. A revised action needs a new idempotency key. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `deleted` | string | Yes | deleted when this request removed the record; already_deleted when it was already absent. Allowed: `"deleted"`, `"already_deleted"`. | | `cascaded` | array of string | No | IDs of dependent records deleted with this 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `conflict` | A supplied expected value no longer matches. Read the record again before deciding whether to retry. | ## Next steps - [List notes](/developers/reference/customers/ListNotes) - [Get note](/developers/reference/customers/GetNote) - [Create note](/developers/reference/customers/CreateNote) - [Upsert note](/developers/reference/customers/UpsertNote) - [Update note](/developers/reference/customers/UpdateNote) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.DeleteNote' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_note_example" }' ``` #### TypeScript ```typescript 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/customers.DeleteNote", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_note_example" }), }); 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_note_example" } request = Request( "https://api.brigg.app/v1/operations/customers.DeleteNote", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "deleted": "deleted" } ``` ### Delete only if unchanged Use a value you actually read. A concurrent change refuses the write with 409 conflict. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.DeleteNote' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_note_example", "expected": { "body": "Alex confirmed that the pilot will start on 19 October." } }' ``` #### TypeScript ```typescript 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/customers.DeleteNote", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_note_example", "expected": { "body": "Alex confirmed that the pilot will start on 19 October." } }), }); 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_note_example", "expected": { "body": "Alex confirmed that the pilot will start on 19 October." } } request = Request( "https://api.brigg.app/v1/operations/customers.DeleteNote", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "deleted": "deleted" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:Note` record. Find it with [customers.ListNotes](/developers/reference/customers/ListNotes). Use the record's top-level `id`, not a business field or account ID." }, "expected": { "type": "object", "description": "Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {\"$absent\":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource.", "additionalProperties": false, "properties": { "body": { "description": "Commit only if the previous body value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Customer activity note content, which may contain Markdown. Preserve the text and render it safely; this is not HTML." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "occurred_at": { "description": "Commit only if the previous occurred_at value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Date of the activity described by the note, in YYYY-MM-DD format. Creation time is recorded separately." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "parent_type": { "description": "Commit only if the previous parent_type value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "CRM parent type: core:Company, core:Person or core:Deal. Pair with parent_id. These resource identifiers differ from public operation namespaces." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "parent_id": { "description": "Commit only if the previous parent_id value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Record ID within parent_type. The type and ID must identify the same parent." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "author_ref": { "description": "Commit only if the previous author_ref value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Person record representing the note's author, not the author's account ID. Brigg supplies the acting member's Person reference on creation when omitted." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] } } } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_note_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "deleted": { "type": "string", "enum": [ "deleted", "already_deleted" ], "description": "deleted when this request removed the record; already_deleted when it was already absent." }, "cascaded": { "type": "array", "items": { "type": "string" }, "description": "IDs of dependent records deleted with this record." } }, "required": [ "deleted" ], "additionalProperties": false, "examples": [ { "deleted": "deleted" } ] } ``` --- # Update note Update a note by ID. Omitted fields stay unchanged; use unset to remove fields and expected to prevent overwriting a concurrent change. POST https://api.brigg.app/v1/operations/customers.UpdateNote ## Access & visibility Allow `customers.UpdateNote` on your API key. Resource read permissions: `core:Note`. Resource write permissions: `core:Note`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:Note` record. Find it with [customers.ListNotes](/developers/reference/customers/ListNotes). Use the record's top-level `id`, not a business field or account ID. | | `data` | [Note](#note-request-data) | No | The fields to set. | | `unset` | array of string | No | Keys of `data` to remove. Each item: `"body"`, `"occurred_at"`, `"parent_type"`, `"parent_id"`, `"author_ref"`. | | `expected` | [object](#request-expected) | No | Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {"$absent":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource. | ### Note · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `body` | string | No | Customer activity note content, which may contain Markdown. Preserve the text and render it safely; this is not HTML. | | `occurred_at` | string | No | Date of the activity described by the note, in YYYY-MM-DD format. Creation time is recorded separately. | | `parent_type` | string | No | CRM parent type: core:Company, core:Person or core:Deal. Pair with parent_id. These resource identifiers differ from public operation namespaces. | | `parent_id` | string | No | Record ID within parent_type. The type and ID must identify the same parent. | | `author_ref` | string | No | Person record representing the note's author, not the author's account ID. Brigg supplies the acting member's Person reference on creation when omitted. | ### request.expected | Field | Type | Required | Description | | --- | --- | --- | --- | | `body` | string or [object](#request-expected-body) | No | Commit only if the previous body value matches; use $absent to require that this field is missing. | | `occurred_at` | string or [object](#request-expected-occurred-at) | No | Commit only if the previous occurred_at value matches; use $absent to require that this field is missing. | | `parent_type` | string or [object](#request-expected-parent-type) | No | Commit only if the previous parent_type value matches; use $absent to require that this field is missing. | | `parent_id` | string or [object](#request-expected-parent-id) | No | Commit only if the previous parent_id value matches; use $absent to require that this field is missing. | | `author_ref` | string or [object](#request-expected-author-ref) | No | Commit only if the previous author_ref value matches; use $absent to require that this field is missing. | ### request.expected.body | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.occurred_at | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.parent_type | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.parent_id | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.author_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ## Update without losing changes Send only the business fields you want to change in `data`; omitted fields stay unchanged. Use `unset` to remove an optional field. Setting a field to null is a different action and is allowed only when its schema permits null. Use `expected` for a conditional update: supply the values you last read for the fields whose concurrent changes would matter. `{"$absent": true}` expects a missing field. A conflict means you must read the record again and decide how to reconcile the change. Keep the same idempotency key when retrying the original action; use a new key for a revised action. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [NoteRecord](#noterecord-response-item) | Yes | The requested record, including its metadata and data fields. | ### NoteRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Note record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Note](#note-response-item-data) | Yes | The record's fields. | ### Note · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `body` | string | Yes | Customer activity note content, which may contain Markdown. Preserve the text and render it safely; this is not HTML. | | `occurred_at` | string | No | Date of the activity described by the note, in YYYY-MM-DD format. Creation time is recorded separately. | | `parent_type` | string | No | CRM parent type: core:Company, core:Person or core:Deal. Pair with parent_id. These resource identifiers differ from public operation namespaces. | | `parent_id` | string | No | Record ID within parent_type. The type and ID must identify the same parent. | | `author_ref` | string | No | Person record representing the note's author, not the author's account ID. Brigg supplies the acting member's Person reference on creation when omitted. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `conflict` | A supplied expected value no longer matches. Read the record again before deciding whether to retry. | ## Next steps - [List notes](/developers/reference/customers/ListNotes) - [Get note](/developers/reference/customers/GetNote) - [Create note](/developers/reference/customers/CreateNote) - [Upsert note](/developers/reference/customers/UpsertNote) - [Delete note](/developers/reference/customers/DeleteNote) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.UpdateNote' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_note_example", "data": { "body": "Alex confirmed the pilot date and delivery checklist." } }' ``` #### TypeScript ```typescript 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/customers.UpdateNote", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_note_example", "data": { "body": "Alex confirmed the pilot date and delivery checklist." } }), }); 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_note_example", "data": { "body": "Alex confirmed the pilot date and delivery checklist." } } request = Request( "https://api.brigg.app/v1/operations/customers.UpdateNote", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_note_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "body": "Alex confirmed the pilot date and delivery checklist.", "occurred_at": "2026-10-06", "parent_type": "core:Company", "parent_id": "e_company_northstar" } } } ``` ### Update only if unchanged Use a value you actually read. A concurrent change refuses the write with 409 conflict. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.UpdateNote' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_note_example", "data": { "body": "Alex confirmed the pilot date and delivery checklist." }, "expected": { "body": "Alex confirmed that the pilot will start on 19 October." } }' ``` #### TypeScript ```typescript 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/customers.UpdateNote", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_note_example", "data": { "body": "Alex confirmed the pilot date and delivery checklist." }, "expected": { "body": "Alex confirmed that the pilot will start on 19 October." } }), }); 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_note_example", "data": { "body": "Alex confirmed the pilot date and delivery checklist." }, "expected": { "body": "Alex confirmed that the pilot will start on 19 October." } } request = Request( "https://api.brigg.app/v1/operations/customers.UpdateNote", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_note_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "body": "Alex confirmed the pilot date and delivery checklist.", "occurred_at": "2026-10-06", "parent_type": "core:Company", "parent_id": "e_company_northstar" } } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:Note` record. Find it with [customers.ListNotes](/developers/reference/customers/ListNotes). Use the record's top-level `id`, not a business field or account ID." }, "data": { "type": "object", "properties": { "body": { "type": "string", "description": "Customer activity note content, which may contain Markdown. Preserve the text and render it safely; this is not HTML." }, "occurred_at": { "type": "string", "description": "Date of the activity described by the note, in YYYY-MM-DD format. Creation time is recorded separately." }, "parent_type": { "type": "string", "description": "CRM parent type: core:Company, core:Person or core:Deal. Pair with parent_id. These resource identifiers differ from public operation namespaces." }, "parent_id": { "type": "string", "description": "Record ID within parent_type. The type and ID must identify the same parent." }, "author_ref": { "type": "string", "description": "Person record representing the note's author, not the author's account ID. Brigg supplies the acting member's Person reference on creation when omitted." } }, "required": [], "additionalProperties": false, "description": "The fields to set.", "title": "Note" }, "unset": { "type": "array", "items": { "type": "string", "enum": [ "body", "occurred_at", "parent_type", "parent_id", "author_ref" ] }, "description": "Keys of `data` to remove." }, "expected": { "type": "object", "description": "Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {\"$absent\":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource.", "additionalProperties": false, "properties": { "body": { "description": "Commit only if the previous body value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Customer activity note content, which may contain Markdown. Preserve the text and render it safely; this is not HTML." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "occurred_at": { "description": "Commit only if the previous occurred_at value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Date of the activity described by the note, in YYYY-MM-DD format. Creation time is recorded separately." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "parent_type": { "description": "Commit only if the previous parent_type value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "CRM parent type: core:Company, core:Person or core:Deal. Pair with parent_id. These resource identifiers differ from public operation namespaces." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "parent_id": { "description": "Commit only if the previous parent_id value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Record ID within parent_type. The type and ID must identify the same parent." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "author_ref": { "description": "Commit only if the previous author_ref value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Person record representing the note's author, not the author's account ID. Brigg supplies the acting member's Person reference on creation when omitted." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] } } } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_note_example", "data": { "body": "Alex confirmed the pilot date and delivery checklist." } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:Note record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "body": { "type": "string", "description": "Customer activity note content, which may contain Markdown. Preserve the text and render it safely; this is not HTML." }, "occurred_at": { "type": "string", "description": "Date of the activity described by the note, in YYYY-MM-DD format. Creation time is recorded separately." }, "parent_type": { "type": "string", "description": "CRM parent type: core:Company, core:Person or core:Deal. Pair with parent_id. These resource identifiers differ from public operation namespaces." }, "parent_id": { "type": "string", "description": "Record ID within parent_type. The type and ID must identify the same parent." }, "author_ref": { "type": "string", "description": "Person record representing the note's author, not the author's account ID. Brigg supplies the acting member's Person reference on creation when omitted." } }, "required": [ "body" ], "additionalProperties": false, "description": "The record's fields.", "title": "Note" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "NoteRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_note_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "body": "Alex confirmed the pilot date and delivery checklist.", "occurred_at": "2026-10-06", "parent_type": "core:Company", "parent_id": "e_company_northstar" } } } ] } ``` --- # Upsert note Create or update a note by a permanent external reference. Matching is exact within the workspace, resource type and ownership scope. Supplied fields replace their values; omitted fields stay unchanged. Deleted records are not recreated. POST https://api.brigg.app/v1/operations/customers.UpsertNote ## Access & visibility Allow `customers.UpsertNote` on your API key. Resource read permissions: `core:Note`. Resource write permissions: `core:Note`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `data` | [Note](#note-request-data) | Yes | The record's fields. | | `private` | boolean | No | Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance. | | `external_ref` | [object](#request-external-ref) | Yes | Permanent, case-sensitive source identity within this workspace, resource type and private/workspace scope. It is independent of API key rotation and retry receipt expiry. | ### Note · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `body` | string | Yes | Customer activity note content, which may contain Markdown. Preserve the text and render it safely; this is not HTML. | | `occurred_at` | string | No | Date of the activity described by the note, in YYYY-MM-DD format. Creation time is recorded separately. | | `parent_type` | string | No | CRM parent type: core:Company, core:Person or core:Deal. Pair with parent_id. These resource identifiers differ from public operation namespaces. | | `parent_id` | string | No | Record ID within parent_type. The type and ID must identify the same parent. | | `author_ref` | string | No | Person record representing the note's author, not the author's account ID. Brigg supplies the acting member's Person reference on creation when omitted. | ### request.external_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `namespace` | string | Yes | A stable name for the source system, such as crm-production. At least 1 character. | | `id` | string | Yes | The record ID in that source system. At least 1 character. | ## Sync with a permanent external reference Choose a stable `external_ref.namespace` for your source system and put its record ID in `external_ref.id`. Matching is case-sensitive and scoped to this workspace, resource type and private/workspace ownership. The reference survives API key replacement and the 30-day retry receipt window. It does not match records by email or name. Send the required create fields each time. A missing reference creates a record; an existing reference updates only supplied fields and preserves everything else. `created` tells you which happened. Use the same idempotency key when retrying a lost response and a new key for a later source change. Concurrent calls cannot create duplicate records. A deleted or inaccessible match is refused; the operation does not restore it or make a replacement. Use the returned `item.id` with the regular update operation when you need `unset` or a conditional `expected` edit. Changing `private` chooses a different ownership scope; it does not transfer an existing record. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [NoteRecord](#noterecord-response-item) | Yes | The requested record, including its metadata and data fields. | | `created` | boolean | Yes | True when this external reference created a record; false when it matched an existing record. | ### NoteRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Note record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Note](#note-response-item-data) | Yes | The record's fields. | ### Note · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `body` | string | Yes | Customer activity note content, which may contain Markdown. Preserve the text and render it safely; this is not HTML. | | `occurred_at` | string | No | Date of the activity described by the note, in YYYY-MM-DD format. Creation time is recorded separately. | | `parent_type` | string | No | CRM parent type: core:Company, core:Person or core:Deal. Pair with parent_id. These resource identifiers differ from public operation namespaces. | | `parent_id` | string | No | Record ID within parent_type. The type and ID must identify the same parent. | | `author_ref` | string | No | Person record representing the note's author, not the author's account ID. Brigg supplies the acting member's Person reference on creation when omitted. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List notes](/developers/reference/customers/ListNotes) - [Get note](/developers/reference/customers/GetNote) - [Create note](/developers/reference/customers/CreateNote) - [Update note](/developers/reference/customers/UpdateNote) - [Delete note](/developers/reference/customers/DeleteNote) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### First sync Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.UpsertNote' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "body": "Alex confirmed that the pilot will start on 19 October.", "occurred_at": "2026-10-06", "parent_type": "core:Company", "parent_id": "e_company_northstar" } }' ``` #### TypeScript ```typescript 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/customers.UpsertNote", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "body": "Alex confirmed that the pilot will start on 19 October.", "occurred_at": "2026-10-06", "parent_type": "core:Company", "parent_id": "e_company_northstar" } }), }); 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 = { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "body": "Alex confirmed that the pilot will start on 19 October.", "occurred_at": "2026-10-06", "parent_type": "core:Company", "parent_id": "e_company_northstar" } } request = Request( "https://api.brigg.app/v1/operations/customers.UpsertNote", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_note_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "body": "Alex confirmed that the pilot will start on 19 October.", "occurred_at": "2026-10-06", "parent_type": "core:Company", "parent_id": "e_company_northstar" } }, "created": true } ``` ### Later sync The same external reference returns the same record ID. Use a new idempotency key for a later source change. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.UpsertNote' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "body": "Alex confirmed that the pilot will start on 19 October.", "occurred_at": "2026-10-06", "parent_type": "core:Company", "parent_id": "e_company_northstar" } }' ``` #### TypeScript ```typescript 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/customers.UpsertNote", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "body": "Alex confirmed that the pilot will start on 19 October.", "occurred_at": "2026-10-06", "parent_type": "core:Company", "parent_id": "e_company_northstar" } }), }); 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 = { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "body": "Alex confirmed that the pilot will start on 19 October.", "occurred_at": "2026-10-06", "parent_type": "core:Company", "parent_id": "e_company_northstar" } } request = Request( "https://api.brigg.app/v1/operations/customers.UpsertNote", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_note_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "body": "Alex confirmed that the pilot will start on 19 October.", "occurred_at": "2026-10-06", "parent_type": "core:Company", "parent_id": "e_company_northstar" } }, "created": false } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "data": { "type": "object", "properties": { "body": { "type": "string", "description": "Customer activity note content, which may contain Markdown. Preserve the text and render it safely; this is not HTML." }, "occurred_at": { "type": "string", "description": "Date of the activity described by the note, in YYYY-MM-DD format. Creation time is recorded separately." }, "parent_type": { "type": "string", "description": "CRM parent type: core:Company, core:Person or core:Deal. Pair with parent_id. These resource identifiers differ from public operation namespaces." }, "parent_id": { "type": "string", "description": "Record ID within parent_type. The type and ID must identify the same parent." }, "author_ref": { "type": "string", "description": "Person record representing the note's author, not the author's account ID. Brigg supplies the acting member's Person reference on creation when omitted." } }, "required": [ "body" ], "additionalProperties": false, "description": "The record's fields.", "title": "Note" }, "private": { "type": "boolean", "description": "Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance." }, "external_ref": { "type": "object", "description": "Permanent, case-sensitive source identity within this workspace, resource type and private/workspace scope. It is independent of API key rotation and retry receipt expiry.", "properties": { "namespace": { "type": "string", "minLength": 1, "description": "A stable name for the source system, such as crm-production." }, "id": { "type": "string", "minLength": 1, "description": "The record ID in that source system." } }, "required": [ "namespace", "id" ], "additionalProperties": false } }, "required": [ "external_ref", "data" ], "additionalProperties": false, "examples": [ { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "body": "Alex confirmed that the pilot will start on 19 October.", "occurred_at": "2026-10-06", "parent_type": "core:Company", "parent_id": "e_company_northstar" } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:Note record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "body": { "type": "string", "description": "Customer activity note content, which may contain Markdown. Preserve the text and render it safely; this is not HTML." }, "occurred_at": { "type": "string", "description": "Date of the activity described by the note, in YYYY-MM-DD format. Creation time is recorded separately." }, "parent_type": { "type": "string", "description": "CRM parent type: core:Company, core:Person or core:Deal. Pair with parent_id. These resource identifiers differ from public operation namespaces." }, "parent_id": { "type": "string", "description": "Record ID within parent_type. The type and ID must identify the same parent." }, "author_ref": { "type": "string", "description": "Person record representing the note's author, not the author's account ID. Brigg supplies the acting member's Person reference on creation when omitted." } }, "required": [ "body" ], "additionalProperties": false, "description": "The record's fields.", "title": "Note" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "NoteRecord" }, "created": { "type": "boolean", "description": "True when this external reference created a record; false when it matched an existing record." } }, "required": [ "item", "created" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_note_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "body": "Alex confirmed that the pilot will start on 19 October.", "occurred_at": "2026-10-06", "parent_type": "core:Company", "parent_id": "e_company_northstar" } }, "created": true } ] } ``` --- # Get person Read a person by ID. Returns item: null when no visible record matches. POST https://api.brigg.app/v1/operations/customers.GetPerson ## Access & visibility Allow `customers.GetPerson` on your API key. Resource read permissions: `core:Person`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople). Use the record's top-level `id`, not a business field or account ID. | ## Response Returns **200 OK** with a JSON body. `item: null` means there is no matching record visible to this caller. It does not reveal whether an inaccessible record exists. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. A Person record is a customer/contact identity, not an account ID for member delegation. System-managed member contacts cannot be edited as ordinary customer records. Creating a Person does not upsert by email or guarantee email uniqueness. Before creating from an external system, search [List people](/developers/reference/customers/ListPeople) and retain the returned record ID for subsequent updates. A name or a shared mailbox is not a unique person's identity. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [PersonRecord](#personrecord-response-item) or null | Yes | null when no such record | ### PersonRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Person record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Person](#person-response-item-data) | Yes | The record's fields. | ### Person · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `display_name` | string | Yes | Full name shown for the contact. | | `email` | string | No | Email address. | | `emails` | array of string | No | Additional email addresses. | | `phone` | string | No | Phone number including its country calling code. | | `title` | string | No | The contact's job title. | | `description` | string | No | Notes describing this contact's role or relationship to your business. | | `linkedin_url` | string | No | URL of the contact's LinkedIn profile. | | `company_ref` | string | No | ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | | `bio` | [object](#response-item-data-bio) | No | A short professional profile with a summary and key facts. | ### response.item.data.bio | Field | Type | Required | Description | | --- | --- | --- | --- | | `summary` | string | No | Short summary of the source information. | | `highlights` | array of string | No | Key points extracted from the source information. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [List people](/developers/reference/customers/ListPeople) - [Create person](/developers/reference/customers/CreatePerson) - [Upsert person](/developers/reference/customers/UpsertPerson) - [Update person](/developers/reference/customers/UpdatePerson) - [Delete person](/developers/reference/customers/DeletePerson) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.GetPerson' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "e_person_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.GetPerson", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "id": "e_person_example" }), }); 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 payload = { "id": "e_person_example" } request = Request( "https://api.brigg.app/v1/operations/customers.GetPerson", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "item": { "id": "e_person_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "display_name": "Alex Morgan", "email": "alex@example.com", "title": "Operations manager", "company_ref": "e_company_example" } } } ``` ### No visible record A missing or inaccessible record returns item: null. Do not treat this as proof that a record exists for another member. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.GetPerson' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "e_person_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.GetPerson", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "id": "e_person_example" }), }); 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 payload = { "id": "e_person_example" } request = Request( "https://api.brigg.app/v1/operations/customers.GetPerson", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "item": null } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople). Use the record's top-level `id`, not a business field or account ID." } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_person_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": [ "object", "null" ], "properties": { "id": { "type": "string", "description": "Stable core:Person record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "display_name": { "type": "string", "description": "Full name shown for the contact." }, "email": { "type": "string", "description": "Email address." }, "emails": { "type": "array", "items": { "type": "string" }, "description": "Additional email addresses." }, "phone": { "type": "string", "description": "Phone number including its country calling code." }, "title": { "type": "string", "description": "The contact's job title." }, "description": { "type": "string", "description": "Notes describing this contact's role or relationship to your business." }, "linkedin_url": { "type": "string", "description": "URL of the contact's LinkedIn profile." }, "company_ref": { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, "bio": { "type": "object", "properties": { "summary": { "type": "string", "description": "Short summary of the source information." }, "highlights": { "type": "array", "items": { "type": "string" }, "description": "Key points extracted from the source information." } }, "additionalProperties": false, "description": "A short professional profile with a summary and key facts." } }, "required": [ "display_name" ], "additionalProperties": false, "description": "The record's fields.", "title": "Person" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "null when no such record", "title": "PersonRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_person_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "display_name": "Alex Morgan", "email": "alex@example.com", "title": "Operations manager", "company_ref": "e_company_example" } } } ] } ``` --- # List people List people visible to the credential, with filtering, sorting and cursor pagination. POST https://api.brigg.app/v1/operations/customers.ListPeople ## Access & visibility Allow `customers.ListPeople` on your API key. Resource read permissions: `core:Person`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `filters` | array of [object](#request-filters) | No | Conditions the row must ALL satisfy. | | `sort` | [object](#request-sort) | No | Sort order for the results. Defaults to updated_at descending, with id as a tie-breaker. | | `limit` | integer | No | Maximum number of results to return in this page. Continue with next_cursor when returned. Default: `100`. Minimum: 1. | | `cursor` | string | No | The `next_cursor` of the previous page. | ### request.filters[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | `data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private. Allowed: `"id"`, `"created_at"`, `"updated_at"`, `"created_by"`, `"private"`, `"data.display_name"`, `"data.email"`, `"data.emails"`, `"data.phone"`, `"data.title"`, `"data.description"`, `"data.linkedin_url"`, `"data.company_ref"`, `"data.tags"`, `"data.bio"`. | | `op` | string | Yes | Comparison operator. Use in with an array, or omit value for is_empty and is_not_empty. Allowed: `"eq"`, `"neq"`, `"contains"`, `"starts_with"`, `"gt"`, `"gte"`, `"lt"`, `"lte"`, `"in"`, `"has"`, `"is_empty"`, `"is_not_empty"`. | | `value` | JSON value | No | The comparison value; an array for `in`; omitted for is_empty / is_not_empty. | ### request.sort | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | `data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private. Allowed: `"id"`, `"created_at"`, `"updated_at"`, `"created_by"`, `"private"`, `"data.display_name"`, `"data.email"`, `"data.emails"`, `"data.phone"`, `"data.title"`, `"data.description"`, `"data.linkedin_url"`, `"data.company_ref"`, `"data.tags"`, `"data.bio"`. | | `direction` | string | No | Sort direction: asc for ascending or desc for descending. Allowed: `"asc"`, `"desc"`. | ## Filtering and sorting All conditions are combined with **AND**. Address business fields as `data.`, and record metadata as `id`, `created_at`, `updated_at`, `created_by` or `private`. A field path names one field; it does not traverse nested objects. | Operator | Meaning | Value | | --- | --- | --- | | `eq` | Equal to a scalar | String, number, boolean or null | | `neq` | Not equal; missing values also match | String, number, boolean or null | | `contains` | Case-insensitive text contains | String; % and _ are literal characters | | `starts_with` | Case-insensitive text prefix | String | | `gt`, `gte` | Greater than / at least | Number or string appropriate to the field | | `lt`, `lte` | Less than / at most | Number or string appropriate to the field | | `in` | Equal to any supplied scalar | Nonempty array of strings, numbers, booleans or null | | `has` | Array contains a string | One string; does not match properties inside array objects | | `is_empty` | Missing, null, empty string or empty array | Omit value | | `is_not_empty` | Has a nonempty value | Omit value | Match the stored field's type. Numeric business timestamps take Unix milliseconds; date-only business fields take `YYYY-MM-DD`. The record metadata fields `created_at` and `updated_at` also accept ISO timestamps for ordered comparisons. Sorting defaults to `updated_at` descending. If you supply `sort.field` without `sort.direction`, direction is `desc`. The record ID breaks ties; missing values sort last. ## Response Returns **200 OK** with a JSON body. An empty `items` array means this page contains no matching visible results. Follow `next_cursor` when present. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. A Person record is a customer/contact identity, not an account ID for member delegation. System-managed member contacts cannot be edited as ordinary customer records. Creating a Person does not upsert by email or guarantee email uniqueness. Before creating from an external system, search [List people](/developers/reference/customers/ListPeople) and retain the returned record ID for subsequent updates. A name or a shared mailbox is not a unique person's identity. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [PersonRecord](#personrecord-response-items) | Yes | Records visible under the credential's grants and the selected data scope, matching the requested filters. Pass next_cursor as cursor to continue when a next cursor is returned. | | `next_cursor` | string | No | Pass this value as cursor to continue with the same filters, sort and credential. Omitted when there are no more results. | ### PersonRecord · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Person record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Person](#person-response-items-data) | Yes | The record's fields. | ### Person · response.items[].data | Field | Type | Required | Description | | --- | --- | --- | --- | | `display_name` | string | Yes | Full name shown for the contact. | | `email` | string | No | Email address. | | `emails` | array of string | No | Additional email addresses. | | `phone` | string | No | Phone number including its country calling code. | | `title` | string | No | The contact's job title. | | `description` | string | No | Notes describing this contact's role or relationship to your business. | | `linkedin_url` | string | No | URL of the contact's LinkedIn profile. | | `company_ref` | string | No | ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | | `bio` | [object](#response-items-data-bio) | No | A short professional profile with a summary and key facts. | ### response.items[].data.bio | Field | Type | Required | Description | | --- | --- | --- | --- | | `summary` | string | No | Short summary of the source information. | | `highlights` | array of string | No | Key points extracted from the source information. | ## Pagination Pass `next_cursor` from the response as `cursor` on the next request. Keep the same filters, sort and acting identity. Stop when `next_cursor` is absent; do not infer completion from the number of items. The default page size is **100**; `limit` must be a positive integer. **Pagination is a live view, not a snapshot.** Changes between pages can move records across page boundaries. Upsert by record ID rather than appending blindly. For recurring synchronization, use an overlapping update window and deduplicate records. Periodically reconcile IDs to detect deletions. [Resource webhooks](/developers/webhooks) can supplement synchronization for eligible workspace-shared records only: they do not export private or project-scoped records. Personal data still needs polling and reconciliation. ```typescript const query = { "limit": 10 }; let cursor; do { const response = await fetch("https://api.brigg.app/v1/operations/customers.ListPeople", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ ...query, ...(cursor ? { cursor } : {}) }), }); const page = await response.json(); if (!response.ok) throw new Error(`${response.status}: ${page.message}`); for (const item of page.items) { console.log(item); // Process or upsert each result. } cursor = page.next_cursor; } while (cursor); ``` ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | | 400 | `cursor_invalid` | Restart pagination with no cursor. | | 400 | `cursor_mismatch` | Use the cursor with the original filters, sort order and credential. | ## Next steps - [Get person](/developers/reference/customers/GetPerson) - [Create person](/developers/reference/customers/CreatePerson) - [Upsert person](/developers/reference/customers/UpsertPerson) - [Update person](/developers/reference/customers/UpdatePerson) - [Delete person](/developers/reference/customers/DeletePerson) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### First page Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.ListPeople' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "limit": 10 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.ListPeople", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "limit": 10 }), }); 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 payload = { "limit": 10 } request = Request( "https://api.brigg.app/v1/operations/customers.ListPeople", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_person_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "display_name": "Alex Morgan", "email": "alex@example.com", "title": "Operations manager", "company_ref": "e_company_example" } } ] } ``` ### Contacts at one company Use the Company record ID returned by List companies. This selects linked customer contacts, not workspace members. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.ListPeople' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "limit": 50, "filters": [ { "field": "data.company_ref", "op": "eq", "value": "e_company_northstar" } ] }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.ListPeople", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "limit": 50, "filters": [ { "field": "data.company_ref", "op": "eq", "value": "e_company_northstar" } ] }), }); 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 payload = { "limit": 50, "filters": [ { "field": "data.company_ref", "op": "eq", "value": "e_company_northstar" } ] } request = Request( "https://api.brigg.app/v1/operations/customers.ListPeople", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_person_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "display_name": "Alex Morgan", "email": "alex@example.com", "title": "Operations manager", "company_ref": "e_company_northstar" } } ] } ``` ### Records updated since a checkpoint 6 October 2026 at 00:00 UTC. Use an overlap window and upsert by ID when synchronizing. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.ListPeople' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.ListPeople", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 }), }); 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 payload = { "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 } request = Request( "https://api.brigg.app/v1/operations/customers.ListPeople", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_person_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "display_name": "Alex Morgan", "email": "alex@example.com", "title": "Operations manager", "company_ref": "e_company_example" } } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "filters": { "type": "array", "items": { "type": "object", "properties": { "field": { "type": "string", "description": "`data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private.", "enum": [ "id", "created_at", "updated_at", "created_by", "private", "data.display_name", "data.email", "data.emails", "data.phone", "data.title", "data.description", "data.linkedin_url", "data.company_ref", "data.tags", "data.bio" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "contains", "starts_with", "gt", "gte", "lt", "lte", "in", "has", "is_empty", "is_not_empty" ], "description": "Comparison operator. Use in with an array, or omit value for is_empty and is_not_empty." }, "value": { "description": "The comparison value; an array for `in`; omitted for is_empty / is_not_empty." } }, "required": [ "field", "op" ], "additionalProperties": false }, "description": "Conditions the row must ALL satisfy." }, "sort": { "type": "object", "properties": { "field": { "type": "string", "description": "`data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private.", "enum": [ "id", "created_at", "updated_at", "created_by", "private", "data.display_name", "data.email", "data.emails", "data.phone", "data.title", "data.description", "data.linkedin_url", "data.company_ref", "data.tags", "data.bio" ] }, "direction": { "type": "string", "enum": [ "asc", "desc" ], "description": "Sort direction: asc for ascending or desc for descending." } }, "required": [ "field" ], "additionalProperties": false, "description": "Sort order for the results. Defaults to updated_at descending, with id as a tie-breaker." }, "limit": { "type": "integer", "minimum": 1, "default": 100, "description": "Maximum number of results to return in this page. Continue with next_cursor when returned." }, "cursor": { "type": "string", "description": "The `next_cursor` of the previous page." } }, "additionalProperties": false, "examples": [ { "limit": 10 } ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:Person record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "display_name": { "type": "string", "description": "Full name shown for the contact." }, "email": { "type": "string", "description": "Email address." }, "emails": { "type": "array", "items": { "type": "string" }, "description": "Additional email addresses." }, "phone": { "type": "string", "description": "Phone number including its country calling code." }, "title": { "type": "string", "description": "The contact's job title." }, "description": { "type": "string", "description": "Notes describing this contact's role or relationship to your business." }, "linkedin_url": { "type": "string", "description": "URL of the contact's LinkedIn profile." }, "company_ref": { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, "bio": { "type": "object", "properties": { "summary": { "type": "string", "description": "Short summary of the source information." }, "highlights": { "type": "array", "items": { "type": "string" }, "description": "Key points extracted from the source information." } }, "additionalProperties": false, "description": "A short professional profile with a summary and key facts." } }, "required": [ "display_name" ], "additionalProperties": false, "description": "The record's fields.", "title": "Person" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "title": "PersonRecord" }, "description": "Records visible under the credential's grants and the selected data scope, matching the requested filters. Pass next_cursor as cursor to continue when a next cursor is returned." }, "next_cursor": { "type": "string", "description": "Pass this value as cursor to continue with the same filters, sort and credential. Omitted when there are no more results." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "id": "e_person_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "display_name": "Alex Morgan", "email": "alex@example.com", "title": "Operations manager", "company_ref": "e_company_example" } } ] } ] } ``` --- # Create person Create a person and return the saved record. POST https://api.brigg.app/v1/operations/customers.CreatePerson ## Access & visibility Allow `customers.CreatePerson` on your API key. Resource read permissions: `core:Person`. Resource write permissions: `core:Person`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `data` | [Person](#person-request-data) | Yes | The record's fields. | | `private` | boolean | No | Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance. | ### Person · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `display_name` | string | Yes | Full name shown for the contact. | | `email` | string | No | Email address. | | `emails` | array of string | No | Additional email addresses. | | `phone` | string | No | Phone number including its country calling code. | | `title` | string | No | The contact's job title. | | `description` | string | No | Notes describing this contact's role or relationship to your business. | | `linkedin_url` | string | No | URL of the contact's LinkedIn profile. | | `company_ref` | string | No | ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | | `bio` | [object](#request-data-bio) | No | A short professional profile with a summary and key facts. | ### request.data.bio | Field | Type | Required | Description | | --- | --- | --- | --- | | `summary` | string | No | Short summary of the source information. | | `highlights` | array of string | No | Key points extracted from the source information. | ## Choose ownership deliberately Omitting `private`, or setting it to false, creates a workspace-shared record. Set `private: true` to create a record owned by the approved acting member. Private records require member delegation; a workspace-only credential cannot own a personal record. The credential’s exact resource grants authorize the write; private ownership and project membership remain enforced. A create is a new record, not an upsert. Reuse the same idempotency key only for retries of that logical creation. For recurring synchronization, use the resource’s upsert operation when available: it matches a permanent external reference. Otherwise keep the returned record ID and use the corresponding update operation for subsequent changes. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. A Person record is a customer/contact identity, not an account ID for member delegation. System-managed member contacts cannot be edited as ordinary customer records. Creating a Person does not upsert by email or guarantee email uniqueness. Before creating from an external system, search [List people](/developers/reference/customers/ListPeople) and retain the returned record ID for subsequent updates. A name or a shared mailbox is not a unique person's identity. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [PersonRecord](#personrecord-response-item) | Yes | The requested record, including its metadata and data fields. | ### PersonRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Person record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Person](#person-response-item-data) | Yes | The record's fields. | ### Person · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `display_name` | string | Yes | Full name shown for the contact. | | `email` | string | No | Email address. | | `emails` | array of string | No | Additional email addresses. | | `phone` | string | No | Phone number including its country calling code. | | `title` | string | No | The contact's job title. | | `description` | string | No | Notes describing this contact's role or relationship to your business. | | `linkedin_url` | string | No | URL of the contact's LinkedIn profile. | | `company_ref` | string | No | ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | | `bio` | [object](#response-item-data-bio) | No | A short professional profile with a summary and key facts. | ### response.item.data.bio | Field | Type | Required | Description | | --- | --- | --- | --- | | `summary` | string | No | Short summary of the source information. | | `highlights` | array of string | No | Key points extracted from the source information. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List people](/developers/reference/customers/ListPeople) - [Get person](/developers/reference/customers/GetPerson) - [Upsert person](/developers/reference/customers/UpsertPerson) - [Update person](/developers/reference/customers/UpdatePerson) - [Delete person](/developers/reference/customers/DeletePerson) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.CreatePerson' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "data": { "display_name": "Alex Morgan", "email": "alex@example.com", "title": "Operations manager", "company_ref": "e_company_example" } }' ``` #### TypeScript ```typescript 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/customers.CreatePerson", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "data": { "display_name": "Alex Morgan", "email": "alex@example.com", "title": "Operations manager", "company_ref": "e_company_example" } }), }); 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 = { "data": { "display_name": "Alex Morgan", "email": "alex@example.com", "title": "Operations manager", "company_ref": "e_company_example" } } request = Request( "https://api.brigg.app/v1/operations/customers.CreatePerson", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_person_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "display_name": "Alex Morgan", "email": "alex@example.com", "title": "Operations manager", "company_ref": "e_company_example" } } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "data": { "type": "object", "properties": { "display_name": { "type": "string", "description": "Full name shown for the contact." }, "email": { "type": "string", "description": "Email address." }, "emails": { "type": "array", "items": { "type": "string" }, "description": "Additional email addresses." }, "phone": { "type": "string", "description": "Phone number including its country calling code." }, "title": { "type": "string", "description": "The contact's job title." }, "description": { "type": "string", "description": "Notes describing this contact's role or relationship to your business." }, "linkedin_url": { "type": "string", "description": "URL of the contact's LinkedIn profile." }, "company_ref": { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, "bio": { "type": "object", "properties": { "summary": { "type": "string", "description": "Short summary of the source information." }, "highlights": { "type": "array", "items": { "type": "string" }, "description": "Key points extracted from the source information." } }, "additionalProperties": false, "description": "A short professional profile with a summary and key facts." } }, "required": [ "display_name" ], "additionalProperties": false, "description": "The record's fields.", "title": "Person" }, "private": { "type": "boolean", "description": "Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance." } }, "required": [ "data" ], "additionalProperties": false, "examples": [ { "data": { "display_name": "Alex Morgan", "email": "alex@example.com", "title": "Operations manager", "company_ref": "e_company_example" } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:Person record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "display_name": { "type": "string", "description": "Full name shown for the contact." }, "email": { "type": "string", "description": "Email address." }, "emails": { "type": "array", "items": { "type": "string" }, "description": "Additional email addresses." }, "phone": { "type": "string", "description": "Phone number including its country calling code." }, "title": { "type": "string", "description": "The contact's job title." }, "description": { "type": "string", "description": "Notes describing this contact's role or relationship to your business." }, "linkedin_url": { "type": "string", "description": "URL of the contact's LinkedIn profile." }, "company_ref": { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, "bio": { "type": "object", "properties": { "summary": { "type": "string", "description": "Short summary of the source information." }, "highlights": { "type": "array", "items": { "type": "string" }, "description": "Key points extracted from the source information." } }, "additionalProperties": false, "description": "A short professional profile with a summary and key facts." } }, "required": [ "display_name" ], "additionalProperties": false, "description": "The record's fields.", "title": "Person" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "PersonRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_person_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "display_name": "Alex Morgan", "email": "alex@example.com", "title": "Operations manager", "company_ref": "e_company_example" } } } ] } ``` --- # Delete person Delete a person by ID. Repeating a deletion returns already_deleted. POST https://api.brigg.app/v1/operations/customers.DeletePerson ## Access & visibility Allow `customers.DeletePerson` on your API key. Resource read permissions: `core:Person`. Resource write permissions: `core:Person`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople). Use the record's top-level `id`, not a business field or account ID. | | `expected` | [object](#request-expected) | No | Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {"$absent":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource. | ### request.expected | Field | Type | Required | Description | | --- | --- | --- | --- | | `display_name` | string or [object](#request-expected-display-name) | No | Commit only if the previous display_name value matches; use $absent to require that this field is missing. | | `email` | string or [object](#request-expected-email) | No | Commit only if the previous email value matches; use $absent to require that this field is missing. | | `emails` | array of string or [object](#request-expected-emails) | No | Commit only if the previous emails value matches; use $absent to require that this field is missing. | | `phone` | string or [object](#request-expected-phone) | No | Commit only if the previous phone value matches; use $absent to require that this field is missing. | | `title` | string or [object](#request-expected-title) | No | Commit only if the previous title value matches; use $absent to require that this field is missing. | | `description` | string or [object](#request-expected-description) | No | Commit only if the previous description value matches; use $absent to require that this field is missing. | | `linkedin_url` | string or [object](#request-expected-linkedin-url) | No | Commit only if the previous linkedin_url value matches; use $absent to require that this field is missing. | | `company_ref` | string or [object](#request-expected-company-ref) | No | Commit only if the previous company_ref value matches; use $absent to require that this field is missing. | | `tags` | array of string or [object](#request-expected-tags) | No | Commit only if the previous tags value matches; use $absent to require that this field is missing. | | `bio` | [object (2 variants)](#request-expected-bio) | No | Commit only if the previous bio value matches; use $absent to require that this field is missing. | ### request.expected.display_name | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.email | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.emails | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.phone | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.title | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.description | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.linkedin_url | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.company_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.tags | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.bio #### Variant 1 | Field | Type | Required | Description | | --- | --- | --- | --- | | `summary` | string | No | Short summary of the source information. | | `highlights` | array of string | No | Key points extracted from the source information. | #### $absent = true | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ## Deletion and retries A successful response reports whether this call removed the record or it was already absent. Check `cascaded` for dependent record IDs returned by the operation. Retrying the same action uses the original idempotency key. A successful deletion is not an archive you can restore through this operation. To avoid deleting a record someone has changed, read it first and put the relevant prior business values in `expected`. Keys are relative to `data`, not prefixed with `data.`. Use {"$absent": true} to require a missing field. A mismatch returns 409 conflict; read again and decide whether deletion is still appropriate. A revised action needs a new idempotency key. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `deleted` | string | Yes | deleted when this request removed the record; already_deleted when it was already absent. Allowed: `"deleted"`, `"already_deleted"`. | | `cascaded` | array of string | No | IDs of dependent records deleted with this 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `conflict` | A supplied expected value no longer matches. Read the record again before deciding whether to retry. | ## Next steps - [List people](/developers/reference/customers/ListPeople) - [Get person](/developers/reference/customers/GetPerson) - [Create person](/developers/reference/customers/CreatePerson) - [Upsert person](/developers/reference/customers/UpsertPerson) - [Update person](/developers/reference/customers/UpdatePerson) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.DeletePerson' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_person_example" }' ``` #### TypeScript ```typescript 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/customers.DeletePerson", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_person_example" }), }); 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_person_example" } request = Request( "https://api.brigg.app/v1/operations/customers.DeletePerson", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "deleted": "deleted" } ``` ### Delete only if unchanged Use a value you actually read. A concurrent change refuses the write with 409 conflict. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.DeletePerson' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_person_example", "expected": { "display_name": "Alex Morgan" } }' ``` #### TypeScript ```typescript 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/customers.DeletePerson", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_person_example", "expected": { "display_name": "Alex Morgan" } }), }); 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_person_example", "expected": { "display_name": "Alex Morgan" } } request = Request( "https://api.brigg.app/v1/operations/customers.DeletePerson", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "deleted": "deleted" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople). Use the record's top-level `id`, not a business field or account ID." }, "expected": { "type": "object", "description": "Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {\"$absent\":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource.", "additionalProperties": false, "properties": { "display_name": { "description": "Commit only if the previous display_name value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Full name shown for the contact." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "email": { "description": "Commit only if the previous email value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Email address." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "emails": { "description": "Commit only if the previous emails value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "type": "string" }, "description": "Additional email addresses." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "phone": { "description": "Commit only if the previous phone value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Phone number including its country calling code." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "title": { "description": "Commit only if the previous title value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "The contact's job title." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "description": { "description": "Commit only if the previous description value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Notes describing this contact's role or relationship to your business." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "linkedin_url": { "description": "Commit only if the previous linkedin_url value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "URL of the contact's LinkedIn profile." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "company_ref": { "description": "Commit only if the previous company_ref value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "tags": { "description": "Commit only if the previous tags value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "bio": { "description": "Commit only if the previous bio value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "object", "properties": { "summary": { "type": "string", "description": "Short summary of the source information." }, "highlights": { "type": "array", "items": { "type": "string" }, "description": "Key points extracted from the source information." } }, "additionalProperties": false, "description": "A short professional profile with a summary and key facts." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] } } } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_person_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "deleted": { "type": "string", "enum": [ "deleted", "already_deleted" ], "description": "deleted when this request removed the record; already_deleted when it was already absent." }, "cascaded": { "type": "array", "items": { "type": "string" }, "description": "IDs of dependent records deleted with this record." } }, "required": [ "deleted" ], "additionalProperties": false, "examples": [ { "deleted": "deleted" } ] } ``` --- # Update person Update a person by ID. Omitted fields stay unchanged; use unset to remove fields and expected to prevent overwriting a concurrent change. POST https://api.brigg.app/v1/operations/customers.UpdatePerson ## Access & visibility Allow `customers.UpdatePerson` on your API key. Resource read permissions: `core:Person`. Resource write permissions: `core:Person`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople). Use the record's top-level `id`, not a business field or account ID. | | `data` | [Person](#person-request-data) | No | The fields to set. | | `unset` | array of string | No | Keys of `data` to remove. Each item: `"display_name"`, `"email"`, `"emails"`, `"phone"`, `"title"`, `"description"`, `"linkedin_url"`, `"company_ref"`, `"tags"`, `"bio"`. | | `expected` | [object](#request-expected) | No | Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {"$absent":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource. | ### Person · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `display_name` | string | No | Full name shown for the contact. | | `email` | string | No | Email address. | | `emails` | array of string | No | Additional email addresses. | | `phone` | string | No | Phone number including its country calling code. | | `title` | string | No | The contact's job title. | | `description` | string | No | Notes describing this contact's role or relationship to your business. | | `linkedin_url` | string | No | URL of the contact's LinkedIn profile. | | `company_ref` | string | No | ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | | `bio` | [object](#request-data-bio) | No | A short professional profile with a summary and key facts. | ### request.data.bio | Field | Type | Required | Description | | --- | --- | --- | --- | | `summary` | string | No | Short summary of the source information. | | `highlights` | array of string | No | Key points extracted from the source information. | ### request.expected | Field | Type | Required | Description | | --- | --- | --- | --- | | `display_name` | string or [object](#request-expected-display-name) | No | Commit only if the previous display_name value matches; use $absent to require that this field is missing. | | `email` | string or [object](#request-expected-email) | No | Commit only if the previous email value matches; use $absent to require that this field is missing. | | `emails` | array of string or [object](#request-expected-emails) | No | Commit only if the previous emails value matches; use $absent to require that this field is missing. | | `phone` | string or [object](#request-expected-phone) | No | Commit only if the previous phone value matches; use $absent to require that this field is missing. | | `title` | string or [object](#request-expected-title) | No | Commit only if the previous title value matches; use $absent to require that this field is missing. | | `description` | string or [object](#request-expected-description) | No | Commit only if the previous description value matches; use $absent to require that this field is missing. | | `linkedin_url` | string or [object](#request-expected-linkedin-url) | No | Commit only if the previous linkedin_url value matches; use $absent to require that this field is missing. | | `company_ref` | string or [object](#request-expected-company-ref) | No | Commit only if the previous company_ref value matches; use $absent to require that this field is missing. | | `tags` | array of string or [object](#request-expected-tags) | No | Commit only if the previous tags value matches; use $absent to require that this field is missing. | | `bio` | [object (2 variants)](#request-expected-bio) | No | Commit only if the previous bio value matches; use $absent to require that this field is missing. | ### request.expected.display_name | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.email | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.emails | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.phone | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.title | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.description | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.linkedin_url | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.company_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.tags | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.bio #### Variant 1 | Field | Type | Required | Description | | --- | --- | --- | --- | | `summary` | string | No | Short summary of the source information. | | `highlights` | array of string | No | Key points extracted from the source information. | #### $absent = true | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ## Update without losing changes Send only the business fields you want to change in `data`; omitted fields stay unchanged. Use `unset` to remove an optional field. Setting a field to null is a different action and is allowed only when its schema permits null. Use `expected` for a conditional update: supply the values you last read for the fields whose concurrent changes would matter. `{"$absent": true}` expects a missing field. A conflict means you must read the record again and decide how to reconcile the change. Keep the same idempotency key when retrying the original action; use a new key for a revised action. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. A Person record is a customer/contact identity, not an account ID for member delegation. System-managed member contacts cannot be edited as ordinary customer records. Creating a Person does not upsert by email or guarantee email uniqueness. Before creating from an external system, search [List people](/developers/reference/customers/ListPeople) and retain the returned record ID for subsequent updates. A name or a shared mailbox is not a unique person's identity. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [PersonRecord](#personrecord-response-item) | Yes | The requested record, including its metadata and data fields. | ### PersonRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Person record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Person](#person-response-item-data) | Yes | The record's fields. | ### Person · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `display_name` | string | Yes | Full name shown for the contact. | | `email` | string | No | Email address. | | `emails` | array of string | No | Additional email addresses. | | `phone` | string | No | Phone number including its country calling code. | | `title` | string | No | The contact's job title. | | `description` | string | No | Notes describing this contact's role or relationship to your business. | | `linkedin_url` | string | No | URL of the contact's LinkedIn profile. | | `company_ref` | string | No | ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | | `bio` | [object](#response-item-data-bio) | No | A short professional profile with a summary and key facts. | ### response.item.data.bio | Field | Type | Required | Description | | --- | --- | --- | --- | | `summary` | string | No | Short summary of the source information. | | `highlights` | array of string | No | Key points extracted from the source information. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `conflict` | A supplied expected value no longer matches. Read the record again before deciding whether to retry. | ## Next steps - [List people](/developers/reference/customers/ListPeople) - [Get person](/developers/reference/customers/GetPerson) - [Create person](/developers/reference/customers/CreatePerson) - [Upsert person](/developers/reference/customers/UpsertPerson) - [Delete person](/developers/reference/customers/DeletePerson) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.UpdatePerson' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_person_example", "data": { "title": "Head of operations" } }' ``` #### TypeScript ```typescript 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/customers.UpdatePerson", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_person_example", "data": { "title": "Head of operations" } }), }); 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_person_example", "data": { "title": "Head of operations" } } request = Request( "https://api.brigg.app/v1/operations/customers.UpdatePerson", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_person_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "display_name": "Alex Morgan", "email": "alex@example.com", "title": "Head of operations", "company_ref": "e_company_example" } } } ``` ### Update only if unchanged Use a value you actually read. A concurrent change refuses the write with 409 conflict. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.UpdatePerson' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_person_example", "data": { "title": "Head of operations" }, "expected": { "display_name": "Alex Morgan" } }' ``` #### TypeScript ```typescript 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/customers.UpdatePerson", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_person_example", "data": { "title": "Head of operations" }, "expected": { "display_name": "Alex Morgan" } }), }); 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_person_example", "data": { "title": "Head of operations" }, "expected": { "display_name": "Alex Morgan" } } request = Request( "https://api.brigg.app/v1/operations/customers.UpdatePerson", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_person_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "display_name": "Alex Morgan", "email": "alex@example.com", "title": "Head of operations", "company_ref": "e_company_example" } } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople). Use the record's top-level `id`, not a business field or account ID." }, "data": { "type": "object", "properties": { "display_name": { "type": "string", "description": "Full name shown for the contact." }, "email": { "type": "string", "description": "Email address." }, "emails": { "type": "array", "items": { "type": "string" }, "description": "Additional email addresses." }, "phone": { "type": "string", "description": "Phone number including its country calling code." }, "title": { "type": "string", "description": "The contact's job title." }, "description": { "type": "string", "description": "Notes describing this contact's role or relationship to your business." }, "linkedin_url": { "type": "string", "description": "URL of the contact's LinkedIn profile." }, "company_ref": { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, "bio": { "type": "object", "properties": { "summary": { "type": "string", "description": "Short summary of the source information." }, "highlights": { "type": "array", "items": { "type": "string" }, "description": "Key points extracted from the source information." } }, "additionalProperties": false, "description": "A short professional profile with a summary and key facts." } }, "required": [], "additionalProperties": false, "description": "The fields to set.", "title": "Person" }, "unset": { "type": "array", "items": { "type": "string", "enum": [ "display_name", "email", "emails", "phone", "title", "description", "linkedin_url", "company_ref", "tags", "bio" ] }, "description": "Keys of `data` to remove." }, "expected": { "type": "object", "description": "Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {\"$absent\":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource.", "additionalProperties": false, "properties": { "display_name": { "description": "Commit only if the previous display_name value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Full name shown for the contact." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "email": { "description": "Commit only if the previous email value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Email address." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "emails": { "description": "Commit only if the previous emails value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "type": "string" }, "description": "Additional email addresses." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "phone": { "description": "Commit only if the previous phone value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Phone number including its country calling code." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "title": { "description": "Commit only if the previous title value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "The contact's job title." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "description": { "description": "Commit only if the previous description value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Notes describing this contact's role or relationship to your business." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "linkedin_url": { "description": "Commit only if the previous linkedin_url value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "URL of the contact's LinkedIn profile." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "company_ref": { "description": "Commit only if the previous company_ref value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "tags": { "description": "Commit only if the previous tags value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "bio": { "description": "Commit only if the previous bio value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "object", "properties": { "summary": { "type": "string", "description": "Short summary of the source information." }, "highlights": { "type": "array", "items": { "type": "string" }, "description": "Key points extracted from the source information." } }, "additionalProperties": false, "description": "A short professional profile with a summary and key facts." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] } } } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_person_example", "data": { "title": "Head of operations" } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:Person record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "display_name": { "type": "string", "description": "Full name shown for the contact." }, "email": { "type": "string", "description": "Email address." }, "emails": { "type": "array", "items": { "type": "string" }, "description": "Additional email addresses." }, "phone": { "type": "string", "description": "Phone number including its country calling code." }, "title": { "type": "string", "description": "The contact's job title." }, "description": { "type": "string", "description": "Notes describing this contact's role or relationship to your business." }, "linkedin_url": { "type": "string", "description": "URL of the contact's LinkedIn profile." }, "company_ref": { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, "bio": { "type": "object", "properties": { "summary": { "type": "string", "description": "Short summary of the source information." }, "highlights": { "type": "array", "items": { "type": "string" }, "description": "Key points extracted from the source information." } }, "additionalProperties": false, "description": "A short professional profile with a summary and key facts." } }, "required": [ "display_name" ], "additionalProperties": false, "description": "The record's fields.", "title": "Person" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "PersonRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_person_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "display_name": "Alex Morgan", "email": "alex@example.com", "title": "Head of operations", "company_ref": "e_company_example" } } } ] } ``` --- # Upsert person Create or update a person by a permanent external reference. Matching is exact within the workspace, resource type and ownership scope. Supplied fields replace their values; omitted fields stay unchanged. Deleted records are not recreated. POST https://api.brigg.app/v1/operations/customers.UpsertPerson ## Access & visibility Allow `customers.UpsertPerson` on your API key. Resource read permissions: `core:Person`. Resource write permissions: `core:Person`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `data` | [Person](#person-request-data) | Yes | The record's fields. | | `private` | boolean | No | Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance. | | `external_ref` | [object](#request-external-ref) | Yes | Permanent, case-sensitive source identity within this workspace, resource type and private/workspace scope. It is independent of API key rotation and retry receipt expiry. | ### Person · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `display_name` | string | Yes | Full name shown for the contact. | | `email` | string | No | Email address. | | `emails` | array of string | No | Additional email addresses. | | `phone` | string | No | Phone number including its country calling code. | | `title` | string | No | The contact's job title. | | `description` | string | No | Notes describing this contact's role or relationship to your business. | | `linkedin_url` | string | No | URL of the contact's LinkedIn profile. | | `company_ref` | string | No | ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | | `bio` | [object](#request-data-bio) | No | A short professional profile with a summary and key facts. | ### request.data.bio | Field | Type | Required | Description | | --- | --- | --- | --- | | `summary` | string | No | Short summary of the source information. | | `highlights` | array of string | No | Key points extracted from the source information. | ### request.external_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `namespace` | string | Yes | A stable name for the source system, such as crm-production. At least 1 character. | | `id` | string | Yes | The record ID in that source system. At least 1 character. | ## Sync with a permanent external reference Choose a stable `external_ref.namespace` for your source system and put its record ID in `external_ref.id`. Matching is case-sensitive and scoped to this workspace, resource type and private/workspace ownership. The reference survives API key replacement and the 30-day retry receipt window. It does not match records by email or name. Send the required create fields each time. A missing reference creates a record; an existing reference updates only supplied fields and preserves everything else. `created` tells you which happened. Use the same idempotency key when retrying a lost response and a new key for a later source change. Concurrent calls cannot create duplicate records. A deleted or inaccessible match is refused; the operation does not restore it or make a replacement. Use the returned `item.id` with the regular update operation when you need `unset` or a conditional `expected` edit. Changing `private` chooses a different ownership scope; it does not transfer an existing record. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. A Person record is a customer/contact identity, not an account ID for member delegation. System-managed member contacts cannot be edited as ordinary customer records. Creating a Person does not upsert by email or guarantee email uniqueness. Before creating from an external system, search [List people](/developers/reference/customers/ListPeople) and retain the returned record ID for subsequent updates. A name or a shared mailbox is not a unique person's identity. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [PersonRecord](#personrecord-response-item) | Yes | The requested record, including its metadata and data fields. | | `created` | boolean | Yes | True when this external reference created a record; false when it matched an existing record. | ### PersonRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Person record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Person](#person-response-item-data) | Yes | The record's fields. | ### Person · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `display_name` | string | Yes | Full name shown for the contact. | | `email` | string | No | Email address. | | `emails` | array of string | No | Additional email addresses. | | `phone` | string | No | Phone number including its country calling code. | | `title` | string | No | The contact's job title. | | `description` | string | No | Notes describing this contact's role or relationship to your business. | | `linkedin_url` | string | No | URL of the contact's LinkedIn profile. | | `company_ref` | string | No | ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | | `bio` | [object](#response-item-data-bio) | No | A short professional profile with a summary and key facts. | ### response.item.data.bio | Field | Type | Required | Description | | --- | --- | --- | --- | | `summary` | string | No | Short summary of the source information. | | `highlights` | array of string | No | Key points extracted from the source information. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List people](/developers/reference/customers/ListPeople) - [Get person](/developers/reference/customers/GetPerson) - [Create person](/developers/reference/customers/CreatePerson) - [Update person](/developers/reference/customers/UpdatePerson) - [Delete person](/developers/reference/customers/DeletePerson) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### First sync Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.UpsertPerson' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "display_name": "Alex Morgan", "email": "alex@example.com", "title": "Operations manager", "company_ref": "e_company_example" } }' ``` #### TypeScript ```typescript 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/customers.UpsertPerson", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "display_name": "Alex Morgan", "email": "alex@example.com", "title": "Operations manager", "company_ref": "e_company_example" } }), }); 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 = { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "display_name": "Alex Morgan", "email": "alex@example.com", "title": "Operations manager", "company_ref": "e_company_example" } } request = Request( "https://api.brigg.app/v1/operations/customers.UpsertPerson", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_person_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "display_name": "Alex Morgan", "email": "alex@example.com", "title": "Operations manager", "company_ref": "e_company_example" } }, "created": true } ``` ### Later sync The same external reference returns the same record ID. Use a new idempotency key for a later source change. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.UpsertPerson' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "display_name": "Alex Morgan", "email": "alex@example.com", "title": "Operations manager", "company_ref": "e_company_example" } }' ``` #### TypeScript ```typescript 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/customers.UpsertPerson", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "display_name": "Alex Morgan", "email": "alex@example.com", "title": "Operations manager", "company_ref": "e_company_example" } }), }); 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 = { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "display_name": "Alex Morgan", "email": "alex@example.com", "title": "Operations manager", "company_ref": "e_company_example" } } request = Request( "https://api.brigg.app/v1/operations/customers.UpsertPerson", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_person_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "display_name": "Alex Morgan", "email": "alex@example.com", "title": "Operations manager", "company_ref": "e_company_example" } }, "created": false } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "data": { "type": "object", "properties": { "display_name": { "type": "string", "description": "Full name shown for the contact." }, "email": { "type": "string", "description": "Email address." }, "emails": { "type": "array", "items": { "type": "string" }, "description": "Additional email addresses." }, "phone": { "type": "string", "description": "Phone number including its country calling code." }, "title": { "type": "string", "description": "The contact's job title." }, "description": { "type": "string", "description": "Notes describing this contact's role or relationship to your business." }, "linkedin_url": { "type": "string", "description": "URL of the contact's LinkedIn profile." }, "company_ref": { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, "bio": { "type": "object", "properties": { "summary": { "type": "string", "description": "Short summary of the source information." }, "highlights": { "type": "array", "items": { "type": "string" }, "description": "Key points extracted from the source information." } }, "additionalProperties": false, "description": "A short professional profile with a summary and key facts." } }, "required": [ "display_name" ], "additionalProperties": false, "description": "The record's fields.", "title": "Person" }, "private": { "type": "boolean", "description": "Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance." }, "external_ref": { "type": "object", "description": "Permanent, case-sensitive source identity within this workspace, resource type and private/workspace scope. It is independent of API key rotation and retry receipt expiry.", "properties": { "namespace": { "type": "string", "minLength": 1, "description": "A stable name for the source system, such as crm-production." }, "id": { "type": "string", "minLength": 1, "description": "The record ID in that source system." } }, "required": [ "namespace", "id" ], "additionalProperties": false } }, "required": [ "external_ref", "data" ], "additionalProperties": false, "examples": [ { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "display_name": "Alex Morgan", "email": "alex@example.com", "title": "Operations manager", "company_ref": "e_company_example" } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:Person record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "display_name": { "type": "string", "description": "Full name shown for the contact." }, "email": { "type": "string", "description": "Email address." }, "emails": { "type": "array", "items": { "type": "string" }, "description": "Additional email addresses." }, "phone": { "type": "string", "description": "Phone number including its country calling code." }, "title": { "type": "string", "description": "The contact's job title." }, "description": { "type": "string", "description": "Notes describing this contact's role or relationship to your business." }, "linkedin_url": { "type": "string", "description": "URL of the contact's LinkedIn profile." }, "company_ref": { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, "bio": { "type": "object", "properties": { "summary": { "type": "string", "description": "Short summary of the source information." }, "highlights": { "type": "array", "items": { "type": "string" }, "description": "Key points extracted from the source information." } }, "additionalProperties": false, "description": "A short professional profile with a summary and key facts." } }, "required": [ "display_name" ], "additionalProperties": false, "description": "The record's fields.", "title": "Person" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "PersonRecord" }, "created": { "type": "boolean", "description": "True when this external reference created a record; false when it matched an existing record." } }, "required": [ "item", "created" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_person_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "display_name": "Alex Morgan", "email": "alex@example.com", "title": "Operations manager", "company_ref": "e_company_example" } }, "created": true } ] } ``` --- # Get product Read a product by ID. Returns item: null when no visible record matches. POST https://api.brigg.app/v1/operations/customers.GetProduct ## Access & visibility Allow `customers.GetProduct` on your API key. Resource read permissions: `core:Product`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:Product` record. Find it with [customers.ListProducts](/developers/reference/customers/ListProducts). Use the record's top-level `id`, not a business field or account ID. | ## Response Returns **200 OK** with a JSON body. `item: null` means there is no matching record visible to this caller. It does not reveal whether an inaccessible record exists. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [ProductRecord](#productrecord-response-item) or null | Yes | null when no such record | ### ProductRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Product record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Product](#product-response-item-data) | Yes | The record's fields. | ### Product · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Product or service name shown on a deal or commercial agreement. | | `description` | string | No | Description of the product or service sold. | | `sku` | string | No | Your stock-keeping code for this product or service. | | `unit` | string | No | Unit billed, such as hour, item or session. | | `unit_price_ore` | integer | No | Price for one unit in Norwegian øre. 100000 means NOK 1,000. The product catalogue is NOK-only. | | `revenue_type` | string | No | Whether this amount is charged once or repeats monthly, quarterly or annually. Allowed: `"one_time"`, `"monthly"`, `"quarterly"`, `"annual"`. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [List products](/developers/reference/customers/ListProducts) - [Create product](/developers/reference/customers/CreateProduct) - [Upsert product](/developers/reference/customers/UpsertProduct) - [Update product](/developers/reference/customers/UpdateProduct) - [Delete product](/developers/reference/customers/DeleteProduct) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.GetProduct' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "e_product_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.GetProduct", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "id": "e_product_example" }), }); 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 payload = { "id": "e_product_example" } request = Request( "https://api.brigg.app/v1/operations/customers.GetProduct", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "item": { "id": "e_product_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "name": "Onboarding workshop", "description": "A half-day workshop for the project team.", "sku": "WORKSHOP-01", "unit": "session", "unit_price_ore": 100000, "revenue_type": "one_time" } } } ``` ### No visible record A missing or inaccessible record returns item: null. Do not treat this as proof that a record exists for another member. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.GetProduct' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "e_product_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.GetProduct", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "id": "e_product_example" }), }); 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 payload = { "id": "e_product_example" } request = Request( "https://api.brigg.app/v1/operations/customers.GetProduct", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "item": null } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:Product` record. Find it with [customers.ListProducts](/developers/reference/customers/ListProducts). Use the record's top-level `id`, not a business field or account ID." } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_product_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": [ "object", "null" ], "properties": { "id": { "type": "string", "description": "Stable core:Product record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "name": { "type": "string", "description": "Product or service name shown on a deal or commercial agreement." }, "description": { "type": "string", "description": "Description of the product or service sold." }, "sku": { "type": "string", "description": "Your stock-keeping code for this product or service." }, "unit": { "type": "string", "description": "Unit billed, such as hour, item or session." }, "unit_price_ore": { "type": "integer", "description": "Price for one unit in Norwegian øre. 100000 means NOK 1,000. The product catalogue is NOK-only." }, "revenue_type": { "type": "string", "enum": [ "one_time", "monthly", "quarterly", "annual" ], "description": "Whether this amount is charged once or repeats monthly, quarterly or annually." } }, "required": [ "name" ], "additionalProperties": false, "description": "The record's fields.", "title": "Product" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "null when no such record", "title": "ProductRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_product_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "name": "Onboarding workshop", "description": "A half-day workshop for the project team.", "sku": "WORKSHOP-01", "unit": "session", "unit_price_ore": 100000, "revenue_type": "one_time" } } } ] } ``` --- # List products List products visible to the credential, with filtering, sorting and cursor pagination. POST https://api.brigg.app/v1/operations/customers.ListProducts ## Access & visibility Allow `customers.ListProducts` on your API key. Resource read permissions: `core:Product`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `filters` | array of [object](#request-filters) | No | Conditions the row must ALL satisfy. | | `sort` | [object](#request-sort) | No | Sort order for the results. Defaults to updated_at descending, with id as a tie-breaker. | | `limit` | integer | No | Maximum number of results to return in this page. Continue with next_cursor when returned. Default: `100`. Minimum: 1. | | `cursor` | string | No | The `next_cursor` of the previous page. | ### request.filters[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | `data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private. Allowed: `"id"`, `"created_at"`, `"updated_at"`, `"created_by"`, `"private"`, `"data.name"`, `"data.description"`, `"data.sku"`, `"data.unit"`, `"data.unit_price_ore"`, `"data.revenue_type"`. | | `op` | string | Yes | Comparison operator. Use in with an array, or omit value for is_empty and is_not_empty. Allowed: `"eq"`, `"neq"`, `"contains"`, `"starts_with"`, `"gt"`, `"gte"`, `"lt"`, `"lte"`, `"in"`, `"has"`, `"is_empty"`, `"is_not_empty"`. | | `value` | JSON value | No | The comparison value; an array for `in`; omitted for is_empty / is_not_empty. | ### request.sort | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | `data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private. Allowed: `"id"`, `"created_at"`, `"updated_at"`, `"created_by"`, `"private"`, `"data.name"`, `"data.description"`, `"data.sku"`, `"data.unit"`, `"data.unit_price_ore"`, `"data.revenue_type"`. | | `direction` | string | No | Sort direction: asc for ascending or desc for descending. Allowed: `"asc"`, `"desc"`. | ## Filtering and sorting All conditions are combined with **AND**. Address business fields as `data.`, and record metadata as `id`, `created_at`, `updated_at`, `created_by` or `private`. A field path names one field; it does not traverse nested objects. | Operator | Meaning | Value | | --- | --- | --- | | `eq` | Equal to a scalar | String, number, boolean or null | | `neq` | Not equal; missing values also match | String, number, boolean or null | | `contains` | Case-insensitive text contains | String; % and _ are literal characters | | `starts_with` | Case-insensitive text prefix | String | | `gt`, `gte` | Greater than / at least | Number or string appropriate to the field | | `lt`, `lte` | Less than / at most | Number or string appropriate to the field | | `in` | Equal to any supplied scalar | Nonempty array of strings, numbers, booleans or null | | `has` | Array contains a string | One string; does not match properties inside array objects | | `is_empty` | Missing, null, empty string or empty array | Omit value | | `is_not_empty` | Has a nonempty value | Omit value | Match the stored field's type. Numeric business timestamps take Unix milliseconds; date-only business fields take `YYYY-MM-DD`. The record metadata fields `created_at` and `updated_at` also accept ISO timestamps for ordered comparisons. Sorting defaults to `updated_at` descending. If you supply `sort.field` without `sort.direction`, direction is `desc`. The record ID breaks ties; missing values sort last. ## Response Returns **200 OK** with a JSON body. An empty `items` array means this page contains no matching visible results. Follow `next_cursor` when present. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [ProductRecord](#productrecord-response-items) | Yes | Records visible under the credential's grants and the selected data scope, matching the requested filters. Pass next_cursor as cursor to continue when a next cursor is returned. | | `next_cursor` | string | No | Pass this value as cursor to continue with the same filters, sort and credential. Omitted when there are no more results. | ### ProductRecord · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Product record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Product](#product-response-items-data) | Yes | The record's fields. | ### Product · response.items[].data | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Product or service name shown on a deal or commercial agreement. | | `description` | string | No | Description of the product or service sold. | | `sku` | string | No | Your stock-keeping code for this product or service. | | `unit` | string | No | Unit billed, such as hour, item or session. | | `unit_price_ore` | integer | No | Price for one unit in Norwegian øre. 100000 means NOK 1,000. The product catalogue is NOK-only. | | `revenue_type` | string | No | Whether this amount is charged once or repeats monthly, quarterly or annually. Allowed: `"one_time"`, `"monthly"`, `"quarterly"`, `"annual"`. | ## Pagination Pass `next_cursor` from the response as `cursor` on the next request. Keep the same filters, sort and acting identity. Stop when `next_cursor` is absent; do not infer completion from the number of items. The default page size is **100**; `limit` must be a positive integer. **Pagination is a live view, not a snapshot.** Changes between pages can move records across page boundaries. Upsert by record ID rather than appending blindly. For recurring synchronization, use an overlapping update window and deduplicate records. Periodically reconcile IDs to detect deletions. [Resource webhooks](/developers/webhooks) can supplement synchronization for eligible workspace-shared records only: they do not export private or project-scoped records. Personal data still needs polling and reconciliation. ```typescript const query = { "limit": 10 }; let cursor; do { const response = await fetch("https://api.brigg.app/v1/operations/customers.ListProducts", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ ...query, ...(cursor ? { cursor } : {}) }), }); const page = await response.json(); if (!response.ok) throw new Error(`${response.status}: ${page.message}`); for (const item of page.items) { console.log(item); // Process or upsert each result. } cursor = page.next_cursor; } while (cursor); ``` ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | | 400 | `cursor_invalid` | Restart pagination with no cursor. | | 400 | `cursor_mismatch` | Use the cursor with the original filters, sort order and credential. | ## Next steps - [Get product](/developers/reference/customers/GetProduct) - [Create product](/developers/reference/customers/CreateProduct) - [Upsert product](/developers/reference/customers/UpsertProduct) - [Update product](/developers/reference/customers/UpdateProduct) - [Delete product](/developers/reference/customers/DeleteProduct) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### First page Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.ListProducts' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "limit": 10 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.ListProducts", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "limit": 10 }), }); 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 payload = { "limit": 10 } request = Request( "https://api.brigg.app/v1/operations/customers.ListProducts", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_product_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "name": "Onboarding workshop", "description": "A half-day workshop for the project team.", "sku": "WORKSHOP-01", "unit": "session", "unit_price_ore": 100000, "revenue_type": "one_time" } } ] } ``` ### Find a product by SKU Compare your stock-keeping unit exactly. Store the returned Brigg ID for later references. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.ListProducts' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "limit": 50, "filters": [ { "field": "data.sku", "op": "eq", "value": "CONSULT-HOUR" } ] }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.ListProducts", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "limit": 50, "filters": [ { "field": "data.sku", "op": "eq", "value": "CONSULT-HOUR" } ] }), }); 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 payload = { "limit": 50, "filters": [ { "field": "data.sku", "op": "eq", "value": "CONSULT-HOUR" } ] } request = Request( "https://api.brigg.app/v1/operations/customers.ListProducts", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_product_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "name": "Onboarding workshop", "description": "A half-day workshop for the project team.", "sku": "CONSULT-HOUR", "unit": "session", "unit_price_ore": 100000, "revenue_type": "one_time" } } ] } ``` ### Records updated since a checkpoint 6 October 2026 at 00:00 UTC. Use an overlap window and upsert by ID when synchronizing. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.ListProducts' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.ListProducts", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 }), }); 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 payload = { "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 } request = Request( "https://api.brigg.app/v1/operations/customers.ListProducts", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_product_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "name": "Onboarding workshop", "description": "A half-day workshop for the project team.", "sku": "WORKSHOP-01", "unit": "session", "unit_price_ore": 100000, "revenue_type": "one_time" } } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "filters": { "type": "array", "items": { "type": "object", "properties": { "field": { "type": "string", "description": "`data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private.", "enum": [ "id", "created_at", "updated_at", "created_by", "private", "data.name", "data.description", "data.sku", "data.unit", "data.unit_price_ore", "data.revenue_type" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "contains", "starts_with", "gt", "gte", "lt", "lte", "in", "has", "is_empty", "is_not_empty" ], "description": "Comparison operator. Use in with an array, or omit value for is_empty and is_not_empty." }, "value": { "description": "The comparison value; an array for `in`; omitted for is_empty / is_not_empty." } }, "required": [ "field", "op" ], "additionalProperties": false }, "description": "Conditions the row must ALL satisfy." }, "sort": { "type": "object", "properties": { "field": { "type": "string", "description": "`data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private.", "enum": [ "id", "created_at", "updated_at", "created_by", "private", "data.name", "data.description", "data.sku", "data.unit", "data.unit_price_ore", "data.revenue_type" ] }, "direction": { "type": "string", "enum": [ "asc", "desc" ], "description": "Sort direction: asc for ascending or desc for descending." } }, "required": [ "field" ], "additionalProperties": false, "description": "Sort order for the results. Defaults to updated_at descending, with id as a tie-breaker." }, "limit": { "type": "integer", "minimum": 1, "default": 100, "description": "Maximum number of results to return in this page. Continue with next_cursor when returned." }, "cursor": { "type": "string", "description": "The `next_cursor` of the previous page." } }, "additionalProperties": false, "examples": [ { "limit": 10 } ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:Product record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "name": { "type": "string", "description": "Product or service name shown on a deal or commercial agreement." }, "description": { "type": "string", "description": "Description of the product or service sold." }, "sku": { "type": "string", "description": "Your stock-keeping code for this product or service." }, "unit": { "type": "string", "description": "Unit billed, such as hour, item or session." }, "unit_price_ore": { "type": "integer", "description": "Price for one unit in Norwegian øre. 100000 means NOK 1,000. The product catalogue is NOK-only." }, "revenue_type": { "type": "string", "enum": [ "one_time", "monthly", "quarterly", "annual" ], "description": "Whether this amount is charged once or repeats monthly, quarterly or annually." } }, "required": [ "name" ], "additionalProperties": false, "description": "The record's fields.", "title": "Product" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "title": "ProductRecord" }, "description": "Records visible under the credential's grants and the selected data scope, matching the requested filters. Pass next_cursor as cursor to continue when a next cursor is returned." }, "next_cursor": { "type": "string", "description": "Pass this value as cursor to continue with the same filters, sort and credential. Omitted when there are no more results." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "id": "e_product_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "name": "Onboarding workshop", "description": "A half-day workshop for the project team.", "sku": "WORKSHOP-01", "unit": "session", "unit_price_ore": 100000, "revenue_type": "one_time" } } ] } ] } ``` --- # Create product Create a product and return the saved record. POST https://api.brigg.app/v1/operations/customers.CreateProduct ## Access & visibility Allow `customers.CreateProduct` on your API key. Resource read permissions: `core:Product`. Resource write permissions: `core:Product`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `data` | [Product](#product-request-data) | Yes | The record's fields. | | `private` | boolean | No | Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance. | ### Product · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Product or service name shown on a deal or commercial agreement. | | `description` | string | No | Description of the product or service sold. | | `sku` | string | No | Your stock-keeping code for this product or service. | | `unit` | string | No | Unit billed, such as hour, item or session. | | `unit_price_ore` | integer | No | Price for one unit in Norwegian øre. 100000 means NOK 1,000. The product catalogue is NOK-only. | | `revenue_type` | string | No | Whether this amount is charged once or repeats monthly, quarterly or annually. Allowed: `"one_time"`, `"monthly"`, `"quarterly"`, `"annual"`. | ## Choose ownership deliberately Omitting `private`, or setting it to false, creates a workspace-shared record. Set `private: true` to create a record owned by the approved acting member. Private records require member delegation; a workspace-only credential cannot own a personal record. The credential’s exact resource grants authorize the write; private ownership and project membership remain enforced. A create is a new record, not an upsert. Reuse the same idempotency key only for retries of that logical creation. For recurring synchronization, use the resource’s upsert operation when available: it matches a permanent external reference. Otherwise keep the returned record ID and use the corresponding update operation for subsequent changes. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [ProductRecord](#productrecord-response-item) | Yes | The requested record, including its metadata and data fields. | ### ProductRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Product record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Product](#product-response-item-data) | Yes | The record's fields. | ### Product · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Product or service name shown on a deal or commercial agreement. | | `description` | string | No | Description of the product or service sold. | | `sku` | string | No | Your stock-keeping code for this product or service. | | `unit` | string | No | Unit billed, such as hour, item or session. | | `unit_price_ore` | integer | No | Price for one unit in Norwegian øre. 100000 means NOK 1,000. The product catalogue is NOK-only. | | `revenue_type` | string | No | Whether this amount is charged once or repeats monthly, quarterly or annually. Allowed: `"one_time"`, `"monthly"`, `"quarterly"`, `"annual"`. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List products](/developers/reference/customers/ListProducts) - [Get product](/developers/reference/customers/GetProduct) - [Upsert product](/developers/reference/customers/UpsertProduct) - [Update product](/developers/reference/customers/UpdateProduct) - [Delete product](/developers/reference/customers/DeleteProduct) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.CreateProduct' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "data": { "name": "Onboarding workshop", "description": "A half-day workshop for the project team.", "sku": "WORKSHOP-01", "unit": "session", "unit_price_ore": 100000, "revenue_type": "one_time" } }' ``` #### TypeScript ```typescript 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/customers.CreateProduct", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "data": { "name": "Onboarding workshop", "description": "A half-day workshop for the project team.", "sku": "WORKSHOP-01", "unit": "session", "unit_price_ore": 100000, "revenue_type": "one_time" } }), }); 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 = { "data": { "name": "Onboarding workshop", "description": "A half-day workshop for the project team.", "sku": "WORKSHOP-01", "unit": "session", "unit_price_ore": 100000, "revenue_type": "one_time" } } request = Request( "https://api.brigg.app/v1/operations/customers.CreateProduct", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_product_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "name": "Onboarding workshop", "description": "A half-day workshop for the project team.", "sku": "WORKSHOP-01", "unit": "session", "unit_price_ore": 100000, "revenue_type": "one_time" } } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "data": { "type": "object", "properties": { "name": { "type": "string", "description": "Product or service name shown on a deal or commercial agreement." }, "description": { "type": "string", "description": "Description of the product or service sold." }, "sku": { "type": "string", "description": "Your stock-keeping code for this product or service." }, "unit": { "type": "string", "description": "Unit billed, such as hour, item or session." }, "unit_price_ore": { "type": "integer", "description": "Price for one unit in Norwegian øre. 100000 means NOK 1,000. The product catalogue is NOK-only." }, "revenue_type": { "type": "string", "enum": [ "one_time", "monthly", "quarterly", "annual" ], "description": "Whether this amount is charged once or repeats monthly, quarterly or annually." } }, "required": [ "name" ], "additionalProperties": false, "description": "The record's fields.", "title": "Product" }, "private": { "type": "boolean", "description": "Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance." } }, "required": [ "data" ], "additionalProperties": false, "examples": [ { "data": { "name": "Onboarding workshop", "description": "A half-day workshop for the project team.", "sku": "WORKSHOP-01", "unit": "session", "unit_price_ore": 100000, "revenue_type": "one_time" } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:Product record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "name": { "type": "string", "description": "Product or service name shown on a deal or commercial agreement." }, "description": { "type": "string", "description": "Description of the product or service sold." }, "sku": { "type": "string", "description": "Your stock-keeping code for this product or service." }, "unit": { "type": "string", "description": "Unit billed, such as hour, item or session." }, "unit_price_ore": { "type": "integer", "description": "Price for one unit in Norwegian øre. 100000 means NOK 1,000. The product catalogue is NOK-only." }, "revenue_type": { "type": "string", "enum": [ "one_time", "monthly", "quarterly", "annual" ], "description": "Whether this amount is charged once or repeats monthly, quarterly or annually." } }, "required": [ "name" ], "additionalProperties": false, "description": "The record's fields.", "title": "Product" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "ProductRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_product_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "name": "Onboarding workshop", "description": "A half-day workshop for the project team.", "sku": "WORKSHOP-01", "unit": "session", "unit_price_ore": 100000, "revenue_type": "one_time" } } } ] } ``` --- # Delete product Delete a product by ID. Repeating a deletion returns already_deleted. POST https://api.brigg.app/v1/operations/customers.DeleteProduct ## Access & visibility Allow `customers.DeleteProduct` on your API key. Resource read permissions: `core:Product`. Resource write permissions: `core:Product`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:Product` record. Find it with [customers.ListProducts](/developers/reference/customers/ListProducts). Use the record's top-level `id`, not a business field or account ID. | | `expected` | [object](#request-expected) | No | Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {"$absent":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource. | ### request.expected | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string or [object](#request-expected-name) | No | Commit only if the previous name value matches; use $absent to require that this field is missing. | | `description` | string or [object](#request-expected-description) | No | Commit only if the previous description value matches; use $absent to require that this field is missing. | | `sku` | string or [object](#request-expected-sku) | No | Commit only if the previous sku value matches; use $absent to require that this field is missing. | | `unit` | string or [object](#request-expected-unit) | No | Commit only if the previous unit value matches; use $absent to require that this field is missing. | | `unit_price_ore` | integer or [object](#request-expected-unit-price-ore) | No | Commit only if the previous unit_price_ore value matches; use $absent to require that this field is missing. | | `revenue_type` | string or [object](#request-expected-revenue-type) | No | Commit only if the previous revenue_type value matches; use $absent to require that this field is missing. | ### request.expected.name | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.description | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.sku | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.unit | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.unit_price_ore | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.revenue_type | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ## Deletion and retries A successful response reports whether this call removed the record or it was already absent. Check `cascaded` for dependent record IDs returned by the operation. Retrying the same action uses the original idempotency key. A successful deletion is not an archive you can restore through this operation. To avoid deleting a record someone has changed, read it first and put the relevant prior business values in `expected`. Keys are relative to `data`, not prefixed with `data.`. Use {"$absent": true} to require a missing field. A mismatch returns 409 conflict; read again and decide whether deletion is still appropriate. A revised action needs a new idempotency key. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `deleted` | string | Yes | deleted when this request removed the record; already_deleted when it was already absent. Allowed: `"deleted"`, `"already_deleted"`. | | `cascaded` | array of string | No | IDs of dependent records deleted with this 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `conflict` | A supplied expected value no longer matches. Read the record again before deciding whether to retry. | ## Next steps - [List products](/developers/reference/customers/ListProducts) - [Get product](/developers/reference/customers/GetProduct) - [Create product](/developers/reference/customers/CreateProduct) - [Upsert product](/developers/reference/customers/UpsertProduct) - [Update product](/developers/reference/customers/UpdateProduct) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.DeleteProduct' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_product_example" }' ``` #### TypeScript ```typescript 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/customers.DeleteProduct", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_product_example" }), }); 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_product_example" } request = Request( "https://api.brigg.app/v1/operations/customers.DeleteProduct", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "deleted": "deleted" } ``` ### Delete only if unchanged Use a value you actually read. A concurrent change refuses the write with 409 conflict. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.DeleteProduct' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_product_example", "expected": { "name": "Onboarding workshop" } }' ``` #### TypeScript ```typescript 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/customers.DeleteProduct", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_product_example", "expected": { "name": "Onboarding workshop" } }), }); 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_product_example", "expected": { "name": "Onboarding workshop" } } request = Request( "https://api.brigg.app/v1/operations/customers.DeleteProduct", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "deleted": "deleted" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:Product` record. Find it with [customers.ListProducts](/developers/reference/customers/ListProducts). Use the record's top-level `id`, not a business field or account ID." }, "expected": { "type": "object", "description": "Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {\"$absent\":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource.", "additionalProperties": false, "properties": { "name": { "description": "Commit only if the previous name value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Product or service name shown on a deal or commercial agreement." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "description": { "description": "Commit only if the previous description value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Description of the product or service sold." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "sku": { "description": "Commit only if the previous sku value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Your stock-keeping code for this product or service." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "unit": { "description": "Commit only if the previous unit value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Unit billed, such as hour, item or session." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "unit_price_ore": { "description": "Commit only if the previous unit_price_ore value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "integer", "description": "Price for one unit in Norwegian øre. 100000 means NOK 1,000. The product catalogue is NOK-only." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "revenue_type": { "description": "Commit only if the previous revenue_type value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "enum": [ "one_time", "monthly", "quarterly", "annual" ], "description": "Whether this amount is charged once or repeats monthly, quarterly or annually." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] } } } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_product_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "deleted": { "type": "string", "enum": [ "deleted", "already_deleted" ], "description": "deleted when this request removed the record; already_deleted when it was already absent." }, "cascaded": { "type": "array", "items": { "type": "string" }, "description": "IDs of dependent records deleted with this record." } }, "required": [ "deleted" ], "additionalProperties": false, "examples": [ { "deleted": "deleted" } ] } ``` --- # Update product Update a product by ID. Omitted fields stay unchanged; use unset to remove fields and expected to prevent overwriting a concurrent change. POST https://api.brigg.app/v1/operations/customers.UpdateProduct ## Access & visibility Allow `customers.UpdateProduct` on your API key. Resource read permissions: `core:Product`. Resource write permissions: `core:Product`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:Product` record. Find it with [customers.ListProducts](/developers/reference/customers/ListProducts). Use the record's top-level `id`, not a business field or account ID. | | `data` | [Product](#product-request-data) | No | The fields to set. | | `unset` | array of string | No | Keys of `data` to remove. Each item: `"name"`, `"description"`, `"sku"`, `"unit"`, `"unit_price_ore"`, `"revenue_type"`. | | `expected` | [object](#request-expected) | No | Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {"$absent":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource. | ### Product · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | No | Product or service name shown on a deal or commercial agreement. | | `description` | string | No | Description of the product or service sold. | | `sku` | string | No | Your stock-keeping code for this product or service. | | `unit` | string | No | Unit billed, such as hour, item or session. | | `unit_price_ore` | integer | No | Price for one unit in Norwegian øre. 100000 means NOK 1,000. The product catalogue is NOK-only. | | `revenue_type` | string | No | Whether this amount is charged once or repeats monthly, quarterly or annually. Allowed: `"one_time"`, `"monthly"`, `"quarterly"`, `"annual"`. | ### request.expected | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string or [object](#request-expected-name) | No | Commit only if the previous name value matches; use $absent to require that this field is missing. | | `description` | string or [object](#request-expected-description) | No | Commit only if the previous description value matches; use $absent to require that this field is missing. | | `sku` | string or [object](#request-expected-sku) | No | Commit only if the previous sku value matches; use $absent to require that this field is missing. | | `unit` | string or [object](#request-expected-unit) | No | Commit only if the previous unit value matches; use $absent to require that this field is missing. | | `unit_price_ore` | integer or [object](#request-expected-unit-price-ore) | No | Commit only if the previous unit_price_ore value matches; use $absent to require that this field is missing. | | `revenue_type` | string or [object](#request-expected-revenue-type) | No | Commit only if the previous revenue_type value matches; use $absent to require that this field is missing. | ### request.expected.name | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.description | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.sku | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.unit | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.unit_price_ore | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.revenue_type | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ## Update without losing changes Send only the business fields you want to change in `data`; omitted fields stay unchanged. Use `unset` to remove an optional field. Setting a field to null is a different action and is allowed only when its schema permits null. Use `expected` for a conditional update: supply the values you last read for the fields whose concurrent changes would matter. `{"$absent": true}` expects a missing field. A conflict means you must read the record again and decide how to reconcile the change. Keep the same idempotency key when retrying the original action; use a new key for a revised action. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [ProductRecord](#productrecord-response-item) | Yes | The requested record, including its metadata and data fields. | ### ProductRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Product record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Product](#product-response-item-data) | Yes | The record's fields. | ### Product · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Product or service name shown on a deal or commercial agreement. | | `description` | string | No | Description of the product or service sold. | | `sku` | string | No | Your stock-keeping code for this product or service. | | `unit` | string | No | Unit billed, such as hour, item or session. | | `unit_price_ore` | integer | No | Price for one unit in Norwegian øre. 100000 means NOK 1,000. The product catalogue is NOK-only. | | `revenue_type` | string | No | Whether this amount is charged once or repeats monthly, quarterly or annually. Allowed: `"one_time"`, `"monthly"`, `"quarterly"`, `"annual"`. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `conflict` | A supplied expected value no longer matches. Read the record again before deciding whether to retry. | ## Next steps - [List products](/developers/reference/customers/ListProducts) - [Get product](/developers/reference/customers/GetProduct) - [Create product](/developers/reference/customers/CreateProduct) - [Upsert product](/developers/reference/customers/UpsertProduct) - [Delete product](/developers/reference/customers/DeleteProduct) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.UpdateProduct' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_product_example", "data": { "unit_price_ore": 120000 } }' ``` #### TypeScript ```typescript 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/customers.UpdateProduct", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_product_example", "data": { "unit_price_ore": 120000 } }), }); 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_product_example", "data": { "unit_price_ore": 120000 } } request = Request( "https://api.brigg.app/v1/operations/customers.UpdateProduct", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_product_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "name": "Onboarding workshop", "description": "A half-day workshop for the project team.", "sku": "WORKSHOP-01", "unit": "session", "unit_price_ore": 120000, "revenue_type": "one_time" } } } ``` ### Update only if unchanged Use a value you actually read. A concurrent change refuses the write with 409 conflict. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.UpdateProduct' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_product_example", "data": { "unit_price_ore": 120000 }, "expected": { "name": "Onboarding workshop" } }' ``` #### TypeScript ```typescript 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/customers.UpdateProduct", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_product_example", "data": { "unit_price_ore": 120000 }, "expected": { "name": "Onboarding workshop" } }), }); 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_product_example", "data": { "unit_price_ore": 120000 }, "expected": { "name": "Onboarding workshop" } } request = Request( "https://api.brigg.app/v1/operations/customers.UpdateProduct", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_product_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "name": "Onboarding workshop", "description": "A half-day workshop for the project team.", "sku": "WORKSHOP-01", "unit": "session", "unit_price_ore": 120000, "revenue_type": "one_time" } } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:Product` record. Find it with [customers.ListProducts](/developers/reference/customers/ListProducts). Use the record's top-level `id`, not a business field or account ID." }, "data": { "type": "object", "properties": { "name": { "type": "string", "description": "Product or service name shown on a deal or commercial agreement." }, "description": { "type": "string", "description": "Description of the product or service sold." }, "sku": { "type": "string", "description": "Your stock-keeping code for this product or service." }, "unit": { "type": "string", "description": "Unit billed, such as hour, item or session." }, "unit_price_ore": { "type": "integer", "description": "Price for one unit in Norwegian øre. 100000 means NOK 1,000. The product catalogue is NOK-only." }, "revenue_type": { "type": "string", "enum": [ "one_time", "monthly", "quarterly", "annual" ], "description": "Whether this amount is charged once or repeats monthly, quarterly or annually." } }, "required": [], "additionalProperties": false, "description": "The fields to set.", "title": "Product" }, "unset": { "type": "array", "items": { "type": "string", "enum": [ "name", "description", "sku", "unit", "unit_price_ore", "revenue_type" ] }, "description": "Keys of `data` to remove." }, "expected": { "type": "object", "description": "Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {\"$absent\":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource.", "additionalProperties": false, "properties": { "name": { "description": "Commit only if the previous name value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Product or service name shown on a deal or commercial agreement." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "description": { "description": "Commit only if the previous description value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Description of the product or service sold." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "sku": { "description": "Commit only if the previous sku value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Your stock-keeping code for this product or service." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "unit": { "description": "Commit only if the previous unit value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Unit billed, such as hour, item or session." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "unit_price_ore": { "description": "Commit only if the previous unit_price_ore value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "integer", "description": "Price for one unit in Norwegian øre. 100000 means NOK 1,000. The product catalogue is NOK-only." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "revenue_type": { "description": "Commit only if the previous revenue_type value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "enum": [ "one_time", "monthly", "quarterly", "annual" ], "description": "Whether this amount is charged once or repeats monthly, quarterly or annually." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] } } } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_product_example", "data": { "unit_price_ore": 120000 } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:Product record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "name": { "type": "string", "description": "Product or service name shown on a deal or commercial agreement." }, "description": { "type": "string", "description": "Description of the product or service sold." }, "sku": { "type": "string", "description": "Your stock-keeping code for this product or service." }, "unit": { "type": "string", "description": "Unit billed, such as hour, item or session." }, "unit_price_ore": { "type": "integer", "description": "Price for one unit in Norwegian øre. 100000 means NOK 1,000. The product catalogue is NOK-only." }, "revenue_type": { "type": "string", "enum": [ "one_time", "monthly", "quarterly", "annual" ], "description": "Whether this amount is charged once or repeats monthly, quarterly or annually." } }, "required": [ "name" ], "additionalProperties": false, "description": "The record's fields.", "title": "Product" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "ProductRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_product_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "name": "Onboarding workshop", "description": "A half-day workshop for the project team.", "sku": "WORKSHOP-01", "unit": "session", "unit_price_ore": 120000, "revenue_type": "one_time" } } } ] } ``` --- # Upsert product Create or update a product by a permanent external reference. Matching is exact within the workspace, resource type and ownership scope. Supplied fields replace their values; omitted fields stay unchanged. Deleted records are not recreated. POST https://api.brigg.app/v1/operations/customers.UpsertProduct ## Access & visibility Allow `customers.UpsertProduct` on your API key. Resource read permissions: `core:Product`. Resource write permissions: `core:Product`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `data` | [Product](#product-request-data) | Yes | The record's fields. | | `private` | boolean | No | Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance. | | `external_ref` | [object](#request-external-ref) | Yes | Permanent, case-sensitive source identity within this workspace, resource type and private/workspace scope. It is independent of API key rotation and retry receipt expiry. | ### Product · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Product or service name shown on a deal or commercial agreement. | | `description` | string | No | Description of the product or service sold. | | `sku` | string | No | Your stock-keeping code for this product or service. | | `unit` | string | No | Unit billed, such as hour, item or session. | | `unit_price_ore` | integer | No | Price for one unit in Norwegian øre. 100000 means NOK 1,000. The product catalogue is NOK-only. | | `revenue_type` | string | No | Whether this amount is charged once or repeats monthly, quarterly or annually. Allowed: `"one_time"`, `"monthly"`, `"quarterly"`, `"annual"`. | ### request.external_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `namespace` | string | Yes | A stable name for the source system, such as crm-production. At least 1 character. | | `id` | string | Yes | The record ID in that source system. At least 1 character. | ## Sync with a permanent external reference Choose a stable `external_ref.namespace` for your source system and put its record ID in `external_ref.id`. Matching is case-sensitive and scoped to this workspace, resource type and private/workspace ownership. The reference survives API key replacement and the 30-day retry receipt window. It does not match records by email or name. Send the required create fields each time. A missing reference creates a record; an existing reference updates only supplied fields and preserves everything else. `created` tells you which happened. Use the same idempotency key when retrying a lost response and a new key for a later source change. Concurrent calls cannot create duplicate records. A deleted or inaccessible match is refused; the operation does not restore it or make a replacement. Use the returned `item.id` with the regular update operation when you need `unset` or a conditional `expected` edit. Changing `private` chooses a different ownership scope; it does not transfer an existing record. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [ProductRecord](#productrecord-response-item) | Yes | The requested record, including its metadata and data fields. | | `created` | boolean | Yes | True when this external reference created a record; false when it matched an existing record. | ### ProductRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Product record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Product](#product-response-item-data) | Yes | The record's fields. | ### Product · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Product or service name shown on a deal or commercial agreement. | | `description` | string | No | Description of the product or service sold. | | `sku` | string | No | Your stock-keeping code for this product or service. | | `unit` | string | No | Unit billed, such as hour, item or session. | | `unit_price_ore` | integer | No | Price for one unit in Norwegian øre. 100000 means NOK 1,000. The product catalogue is NOK-only. | | `revenue_type` | string | No | Whether this amount is charged once or repeats monthly, quarterly or annually. Allowed: `"one_time"`, `"monthly"`, `"quarterly"`, `"annual"`. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List products](/developers/reference/customers/ListProducts) - [Get product](/developers/reference/customers/GetProduct) - [Create product](/developers/reference/customers/CreateProduct) - [Update product](/developers/reference/customers/UpdateProduct) - [Delete product](/developers/reference/customers/DeleteProduct) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### First sync Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.UpsertProduct' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "name": "Onboarding workshop", "description": "A half-day workshop for the project team.", "sku": "WORKSHOP-01", "unit": "session", "unit_price_ore": 100000, "revenue_type": "one_time" } }' ``` #### TypeScript ```typescript 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/customers.UpsertProduct", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "name": "Onboarding workshop", "description": "A half-day workshop for the project team.", "sku": "WORKSHOP-01", "unit": "session", "unit_price_ore": 100000, "revenue_type": "one_time" } }), }); 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 = { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "name": "Onboarding workshop", "description": "A half-day workshop for the project team.", "sku": "WORKSHOP-01", "unit": "session", "unit_price_ore": 100000, "revenue_type": "one_time" } } request = Request( "https://api.brigg.app/v1/operations/customers.UpsertProduct", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_product_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "name": "Onboarding workshop", "description": "A half-day workshop for the project team.", "sku": "WORKSHOP-01", "unit": "session", "unit_price_ore": 100000, "revenue_type": "one_time" } }, "created": true } ``` ### Later sync The same external reference returns the same record ID. Use a new idempotency key for a later source change. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.UpsertProduct' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "name": "Onboarding workshop", "description": "A half-day workshop for the project team.", "sku": "WORKSHOP-01", "unit": "session", "unit_price_ore": 100000, "revenue_type": "one_time" } }' ``` #### TypeScript ```typescript 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/customers.UpsertProduct", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "name": "Onboarding workshop", "description": "A half-day workshop for the project team.", "sku": "WORKSHOP-01", "unit": "session", "unit_price_ore": 100000, "revenue_type": "one_time" } }), }); 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 = { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "name": "Onboarding workshop", "description": "A half-day workshop for the project team.", "sku": "WORKSHOP-01", "unit": "session", "unit_price_ore": 100000, "revenue_type": "one_time" } } request = Request( "https://api.brigg.app/v1/operations/customers.UpsertProduct", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_product_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "name": "Onboarding workshop", "description": "A half-day workshop for the project team.", "sku": "WORKSHOP-01", "unit": "session", "unit_price_ore": 100000, "revenue_type": "one_time" } }, "created": false } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "data": { "type": "object", "properties": { "name": { "type": "string", "description": "Product or service name shown on a deal or commercial agreement." }, "description": { "type": "string", "description": "Description of the product or service sold." }, "sku": { "type": "string", "description": "Your stock-keeping code for this product or service." }, "unit": { "type": "string", "description": "Unit billed, such as hour, item or session." }, "unit_price_ore": { "type": "integer", "description": "Price for one unit in Norwegian øre. 100000 means NOK 1,000. The product catalogue is NOK-only." }, "revenue_type": { "type": "string", "enum": [ "one_time", "monthly", "quarterly", "annual" ], "description": "Whether this amount is charged once or repeats monthly, quarterly or annually." } }, "required": [ "name" ], "additionalProperties": false, "description": "The record's fields.", "title": "Product" }, "private": { "type": "boolean", "description": "Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance." }, "external_ref": { "type": "object", "description": "Permanent, case-sensitive source identity within this workspace, resource type and private/workspace scope. It is independent of API key rotation and retry receipt expiry.", "properties": { "namespace": { "type": "string", "minLength": 1, "description": "A stable name for the source system, such as crm-production." }, "id": { "type": "string", "minLength": 1, "description": "The record ID in that source system." } }, "required": [ "namespace", "id" ], "additionalProperties": false } }, "required": [ "external_ref", "data" ], "additionalProperties": false, "examples": [ { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "name": "Onboarding workshop", "description": "A half-day workshop for the project team.", "sku": "WORKSHOP-01", "unit": "session", "unit_price_ore": 100000, "revenue_type": "one_time" } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:Product record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "name": { "type": "string", "description": "Product or service name shown on a deal or commercial agreement." }, "description": { "type": "string", "description": "Description of the product or service sold." }, "sku": { "type": "string", "description": "Your stock-keeping code for this product or service." }, "unit": { "type": "string", "description": "Unit billed, such as hour, item or session." }, "unit_price_ore": { "type": "integer", "description": "Price for one unit in Norwegian øre. 100000 means NOK 1,000. The product catalogue is NOK-only." }, "revenue_type": { "type": "string", "enum": [ "one_time", "monthly", "quarterly", "annual" ], "description": "Whether this amount is charged once or repeats monthly, quarterly or annually." } }, "required": [ "name" ], "additionalProperties": false, "description": "The record's fields.", "title": "Product" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "ProductRecord" }, "created": { "type": "boolean", "description": "True when this external reference created a record; false when it matched an existing record." } }, "required": [ "item", "created" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_product_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "name": "Onboarding workshop", "description": "A half-day workshop for the project team.", "sku": "WORKSHOP-01", "unit": "session", "unit_price_ore": 100000, "revenue_type": "one_time" } }, "created": true } ] } ``` --- # Search registered companies Find registered companies by name or organisation number in Norway and Sweden. Use unavailable to distinguish an unavailable register from no matches. POST https://api.brigg.app/v1/operations/customers.SearchRegisteredCompanies ## Access & visibility Allow `customers.SearchRegisteredCompanies` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `query` | string | Yes | A name, or an organisation number. At most 200 characters. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `hits` | array of [RegisteredCompany](#registeredcompany-response-hits) | Yes | Matching company records, in the returned search order. | | `unavailable` | string | No | The register's own reason it did not answer a number lookup (`not_configured`, `unauthorized`, `unavailable`). | ### RegisteredCompany · response.hits[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `org_number` | string | Yes | Official organization number as text; preserve leading zeros. | | `display_name` | string | Yes | Human-readable name used for this record. | | `name` | string | Yes | Display name. | | `city` | null or string | Yes | Postal town or city. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 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. | ## Next steps [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.SearchRegisteredCompanies' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Brigg-Act-As: $BRIGG_ACT_AS" \ --data-raw '{ "query": "Northstar" }' ``` #### 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 response = await fetch("https://api.brigg.app/v1/operations/customers.SearchRegisteredCompanies", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Brigg-Act-As": actAs, }, body: JSON.stringify({ "query": "Northstar" }), }); 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 payload = { "query": "Northstar" } request = Request( "https://api.brigg.app/v1/operations/customers.SearchRegisteredCompanies", 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"], }, 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 { "hits": [ { "org_number": "999999999", "display_name": "Northstar Consulting AS", "name": "Northstar Consulting AS", "city": null } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "query": { "type": "string", "maxLength": 200, "description": "A name, or an organisation number." } }, "required": [ "query" ], "additionalProperties": false, "examples": [ { "query": "Northstar" } ] } ``` ```json-schema-response { "type": "object", "properties": { "hits": { "type": "array", "items": { "title": "RegisteredCompany", "type": "object", "properties": { "org_number": { "type": "string", "description": "Official organization number as text; preserve leading zeros." }, "display_name": { "type": "string", "description": "Human-readable name used for this record." }, "name": { "type": "string", "description": "Display name." }, "city": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Postal town or city." } }, "required": [ "org_number", "display_name", "name", "city" ], "additionalProperties": false }, "description": "Matching company records, in the returned search order." }, "unavailable": { "type": "string", "description": "The register's own reason it did not answer a number lookup (`not_configured`, `unauthorized`, `unavailable`)." } }, "required": [ "hits" ], "additionalProperties": false, "examples": [ { "hits": [ { "org_number": "999999999", "display_name": "Northstar Consulting AS", "name": "Northstar Consulting AS", "city": null } ] } ] } ``` --- # Enrich record Request missing registry or contact details for a readable customer record. enqueued is false when no work is needed, suitable source data is unavailable, or work is already running or recently completed. Existing business details are not overwritten. Read the record again for updated values. POST https://api.brigg.app/v1/operations/customers.EnrichRecord ## Access & visibility Allow `customers.EnrichRecord` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | A `core:Company` or `core:Person` id. Any other record answers `enqueued: false` — there is nothing to enrich. At least 1 character. At most 80 characters. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | | `enqueued` | boolean | Yes | Whether new background work was started. False can mean no work was needed or a run already exists. | | `type` | string | Yes | The record's qualified type — only `core:Company` and `core:Person` are ever enriched. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | ## Next steps [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.EnrichRecord' \ -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_example" }' ``` #### 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/customers.EnrichRecord", { 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_example" }), }); 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_example" } request = Request( "https://api.brigg.app/v1/operations/customers.EnrichRecord", 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, "enqueued": false, "type": "core:Company" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "maxLength": 80, "description": "A `core:Company` or `core:Person` id. Any other record answers `enqueued: false` — there is nothing to enrich." } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." }, "enqueued": { "type": "boolean", "description": "Whether new background work was started. False can mean no work was needed or a run already exists." }, "type": { "type": "string", "description": "The record's qualified type — only `core:Company` and `core:Person` are ever enriched." } }, "required": [ "ok", "enqueued", "type" ], "additionalProperties": false, "examples": [ { "ok": true, "enqueued": false, "type": "core:Company" } ] } ``` --- # Get sales pipeline Read a sales pipeline by ID. Returns item: null when no visible record matches. POST https://api.brigg.app/v1/operations/customers.GetSalesPipeline ## Access & visibility Allow `customers.GetSalesPipeline` on your API key. Resource read permissions: `core:SalesPipeline`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:SalesPipeline` record. Find it with [customers.ListSalesPipelines](/developers/reference/customers/ListSalesPipelines). Use the record's top-level `id`, not a business field or account ID. | ## Response Returns **200 OK** with a JSON body. `item: null` means there is no matching record visible to this caller. It does not reveal whether an inaccessible record exists. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [SalesPipelineRecord](#salespipelinerecord-response-item) or null | Yes | null when no such record | ### SalesPipelineRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:SalesPipeline record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [SalesPipeline](#salespipeline-response-item-data) | Yes | The record's fields. | ### SalesPipeline · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Name of the sales pipeline. | | `stages` | array of [object](#response-item-data-stages) | No | Sales stages in funnel order. Keep stage IDs stable: deals refer to them. Exactly one won and one lost stage appear last; probability is an integer percentage from 0 to 100 for weighted sales value. | | `is_default` | boolean | No | Whether this is the workspace's default sales pipeline. | ### response.item.data.stages[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable stage ID referenced by deals. Keep it when changing the label. | | `label` | string | Yes | Human-readable stage name. | | `kind` | string | Yes | Whether this stage is open, won or lost. Allowed: `"open"`, `"won"`, `"lost"`. | | `probability` | number | No | Integer percentage from 0 to 100 used for weighted sales value. | | `tone` | string | No | Display color token for the stage. Allowed: `"gray"`, `"blue"`, `"violet"`, `"peach"`, `"soon"`, `"accent"`, `"warn"`. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [List sales pipelines](/developers/reference/customers/ListSalesPipelines) - [Create sales pipeline](/developers/reference/customers/CreateSalesPipeline) - [Upsert sales pipeline](/developers/reference/customers/UpsertSalesPipeline) - [Update sales pipeline](/developers/reference/customers/UpdateSalesPipeline) - [Delete sales pipeline](/developers/reference/customers/DeleteSalesPipeline) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.GetSalesPipeline' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "e_salespipeline_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.GetSalesPipeline", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "id": "e_salespipeline_example" }), }); 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 payload = { "id": "e_salespipeline_example" } request = Request( "https://api.brigg.app/v1/operations/customers.GetSalesPipeline", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "item": { "id": "e_salespipeline_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "Sales pipeline", "is_default": true, "stages": [ { "id": "lead", "label": "Lead", "kind": "open", "probability": 10 }, { "id": "won", "label": "Won", "kind": "won", "probability": 100 }, { "id": "lost", "label": "Lost", "kind": "lost", "probability": 0 } ] } } } ``` ### No visible record A missing or inaccessible record returns item: null. Do not treat this as proof that a record exists for another member. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.GetSalesPipeline' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "e_salespipeline_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.GetSalesPipeline", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "id": "e_salespipeline_example" }), }); 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 payload = { "id": "e_salespipeline_example" } request = Request( "https://api.brigg.app/v1/operations/customers.GetSalesPipeline", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "item": null } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:SalesPipeline` record. Find it with [customers.ListSalesPipelines](/developers/reference/customers/ListSalesPipelines). Use the record's top-level `id`, not a business field or account ID." } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_salespipeline_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": [ "object", "null" ], "properties": { "id": { "type": "string", "description": "Stable core:SalesPipeline record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "name": { "type": "string", "description": "Name of the sales pipeline." }, "stages": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable stage ID referenced by deals. Keep it when changing the label." }, "label": { "type": "string", "description": "Human-readable stage name." }, "kind": { "type": "string", "enum": [ "open", "won", "lost" ], "description": "Whether this stage is open, won or lost." }, "probability": { "type": "number", "description": "Integer percentage from 0 to 100 used for weighted sales value." }, "tone": { "type": "string", "enum": [ "gray", "blue", "violet", "peach", "soon", "accent", "warn" ], "description": "Display color token for the stage." } }, "required": [ "id", "label", "kind" ], "additionalProperties": false }, "description": "Sales stages in funnel order. Keep stage IDs stable: deals refer to them. Exactly one won and one lost stage appear last; probability is an integer percentage from 0 to 100 for weighted sales value." }, "is_default": { "type": "boolean", "description": "Whether this is the workspace's default sales pipeline." } }, "required": [ "name" ], "additionalProperties": false, "description": "The record's fields.", "title": "SalesPipeline" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "null when no such record", "title": "SalesPipelineRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_salespipeline_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "Sales pipeline", "is_default": true, "stages": [ { "id": "lead", "label": "Lead", "kind": "open", "probability": 10 }, { "id": "won", "label": "Won", "kind": "won", "probability": 100 }, { "id": "lost", "label": "Lost", "kind": "lost", "probability": 0 } ] } } } ] } ``` --- # List sales pipelines List sales pipelines visible to the credential, with filtering, sorting and cursor pagination. POST https://api.brigg.app/v1/operations/customers.ListSalesPipelines ## Access & visibility Allow `customers.ListSalesPipelines` on your API key. Resource read permissions: `core:SalesPipeline`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `filters` | array of [object](#request-filters) | No | Conditions the row must ALL satisfy. | | `sort` | [object](#request-sort) | No | Sort order for the results. Defaults to updated_at descending, with id as a tie-breaker. | | `limit` | integer | No | Maximum number of results to return in this page. Continue with next_cursor when returned. Default: `100`. Minimum: 1. | | `cursor` | string | No | The `next_cursor` of the previous page. | ### request.filters[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | `data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private. Allowed: `"id"`, `"created_at"`, `"updated_at"`, `"created_by"`, `"private"`, `"data.name"`, `"data.stages"`, `"data.is_default"`. | | `op` | string | Yes | Comparison operator. Use in with an array, or omit value for is_empty and is_not_empty. Allowed: `"eq"`, `"neq"`, `"contains"`, `"starts_with"`, `"gt"`, `"gte"`, `"lt"`, `"lte"`, `"in"`, `"has"`, `"is_empty"`, `"is_not_empty"`. | | `value` | JSON value | No | The comparison value; an array for `in`; omitted for is_empty / is_not_empty. | ### request.sort | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | `data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private. Allowed: `"id"`, `"created_at"`, `"updated_at"`, `"created_by"`, `"private"`, `"data.name"`, `"data.stages"`, `"data.is_default"`. | | `direction` | string | No | Sort direction: asc for ascending or desc for descending. Allowed: `"asc"`, `"desc"`. | ## Filtering and sorting All conditions are combined with **AND**. Address business fields as `data.`, and record metadata as `id`, `created_at`, `updated_at`, `created_by` or `private`. A field path names one field; it does not traverse nested objects. | Operator | Meaning | Value | | --- | --- | --- | | `eq` | Equal to a scalar | String, number, boolean or null | | `neq` | Not equal; missing values also match | String, number, boolean or null | | `contains` | Case-insensitive text contains | String; % and _ are literal characters | | `starts_with` | Case-insensitive text prefix | String | | `gt`, `gte` | Greater than / at least | Number or string appropriate to the field | | `lt`, `lte` | Less than / at most | Number or string appropriate to the field | | `in` | Equal to any supplied scalar | Nonempty array of strings, numbers, booleans or null | | `has` | Array contains a string | One string; does not match properties inside array objects | | `is_empty` | Missing, null, empty string or empty array | Omit value | | `is_not_empty` | Has a nonempty value | Omit value | Match the stored field's type. Numeric business timestamps take Unix milliseconds; date-only business fields take `YYYY-MM-DD`. The record metadata fields `created_at` and `updated_at` also accept ISO timestamps for ordered comparisons. Sorting defaults to `updated_at` descending. If you supply `sort.field` without `sort.direction`, direction is `desc`. The record ID breaks ties; missing values sort last. ## Response Returns **200 OK** with a JSON body. An empty `items` array means this page contains no matching visible results. Follow `next_cursor` when present. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [SalesPipelineRecord](#salespipelinerecord-response-items) | Yes | Records visible under the credential's grants and the selected data scope, matching the requested filters. Pass next_cursor as cursor to continue when a next cursor is returned. | | `next_cursor` | string | No | Pass this value as cursor to continue with the same filters, sort and credential. Omitted when there are no more results. | ### SalesPipelineRecord · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:SalesPipeline record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [SalesPipeline](#salespipeline-response-items-data) | Yes | The record's fields. | ### SalesPipeline · response.items[].data | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Name of the sales pipeline. | | `stages` | array of [object](#response-items-data-stages) | No | Sales stages in funnel order. Keep stage IDs stable: deals refer to them. Exactly one won and one lost stage appear last; probability is an integer percentage from 0 to 100 for weighted sales value. | | `is_default` | boolean | No | Whether this is the workspace's default sales pipeline. | ### response.items[].data.stages[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable stage ID referenced by deals. Keep it when changing the label. | | `label` | string | Yes | Human-readable stage name. | | `kind` | string | Yes | Whether this stage is open, won or lost. Allowed: `"open"`, `"won"`, `"lost"`. | | `probability` | number | No | Integer percentage from 0 to 100 used for weighted sales value. | | `tone` | string | No | Display color token for the stage. Allowed: `"gray"`, `"blue"`, `"violet"`, `"peach"`, `"soon"`, `"accent"`, `"warn"`. | ## Pagination Pass `next_cursor` from the response as `cursor` on the next request. Keep the same filters, sort and acting identity. Stop when `next_cursor` is absent; do not infer completion from the number of items. The default page size is **100**; `limit` must be a positive integer. **Pagination is a live view, not a snapshot.** Changes between pages can move records across page boundaries. Upsert by record ID rather than appending blindly. For recurring synchronization, use an overlapping update window and deduplicate records. Periodically reconcile IDs to detect deletions. [Resource webhooks](/developers/webhooks) can supplement synchronization for eligible workspace-shared records only: they do not export private or project-scoped records. Personal data still needs polling and reconciliation. ```typescript const query = { "limit": 10 }; let cursor; do { const response = await fetch("https://api.brigg.app/v1/operations/customers.ListSalesPipelines", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ ...query, ...(cursor ? { cursor } : {}) }), }); const page = await response.json(); if (!response.ok) throw new Error(`${response.status}: ${page.message}`); for (const item of page.items) { console.log(item); // Process or upsert each result. } cursor = page.next_cursor; } while (cursor); ``` ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | | 400 | `cursor_invalid` | Restart pagination with no cursor. | | 400 | `cursor_mismatch` | Use the cursor with the original filters, sort order and credential. | ## Next steps - [Get sales pipeline](/developers/reference/customers/GetSalesPipeline) - [Create sales pipeline](/developers/reference/customers/CreateSalesPipeline) - [Upsert sales pipeline](/developers/reference/customers/UpsertSalesPipeline) - [Update sales pipeline](/developers/reference/customers/UpdateSalesPipeline) - [Delete sales pipeline](/developers/reference/customers/DeleteSalesPipeline) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### First page Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.ListSalesPipelines' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "limit": 10 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.ListSalesPipelines", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "limit": 10 }), }); 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 payload = { "limit": 10 } request = Request( "https://api.brigg.app/v1/operations/customers.ListSalesPipelines", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_salespipeline_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "Sales pipeline", "is_default": true, "stages": [ { "id": "lead", "label": "Lead", "kind": "open", "probability": 10 }, { "id": "won", "label": "Won", "kind": "won", "probability": 100 }, { "id": "lost", "label": "Lost", "kind": "lost", "probability": 0 } ] } } ] } ``` ### Find the default pipeline Use the returned ordered stages when displaying the funnel; stage IDs and labels serve different purposes. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.ListSalesPipelines' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "limit": 50, "filters": [ { "field": "data.is_default", "op": "eq", "value": true } ] }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.ListSalesPipelines", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "limit": 50, "filters": [ { "field": "data.is_default", "op": "eq", "value": true } ] }), }); 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 payload = { "limit": 50, "filters": [ { "field": "data.is_default", "op": "eq", "value": True } ] } request = Request( "https://api.brigg.app/v1/operations/customers.ListSalesPipelines", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_salespipeline_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "Sales pipeline", "is_default": true, "stages": [ { "id": "lead", "label": "Lead", "kind": "open", "probability": 10 }, { "id": "won", "label": "Won", "kind": "won", "probability": 100 }, { "id": "lost", "label": "Lost", "kind": "lost", "probability": 0 } ] } } ] } ``` ### Records updated since a checkpoint 6 October 2026 at 00:00 UTC. Use an overlap window and upsert by ID when synchronizing. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.ListSalesPipelines' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.ListSalesPipelines", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 }), }); 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 payload = { "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 } request = Request( "https://api.brigg.app/v1/operations/customers.ListSalesPipelines", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_salespipeline_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "Sales pipeline", "is_default": true, "stages": [ { "id": "lead", "label": "Lead", "kind": "open", "probability": 10 }, { "id": "won", "label": "Won", "kind": "won", "probability": 100 }, { "id": "lost", "label": "Lost", "kind": "lost", "probability": 0 } ] } } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "filters": { "type": "array", "items": { "type": "object", "properties": { "field": { "type": "string", "description": "`data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private.", "enum": [ "id", "created_at", "updated_at", "created_by", "private", "data.name", "data.stages", "data.is_default" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "contains", "starts_with", "gt", "gte", "lt", "lte", "in", "has", "is_empty", "is_not_empty" ], "description": "Comparison operator. Use in with an array, or omit value for is_empty and is_not_empty." }, "value": { "description": "The comparison value; an array for `in`; omitted for is_empty / is_not_empty." } }, "required": [ "field", "op" ], "additionalProperties": false }, "description": "Conditions the row must ALL satisfy." }, "sort": { "type": "object", "properties": { "field": { "type": "string", "description": "`data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private.", "enum": [ "id", "created_at", "updated_at", "created_by", "private", "data.name", "data.stages", "data.is_default" ] }, "direction": { "type": "string", "enum": [ "asc", "desc" ], "description": "Sort direction: asc for ascending or desc for descending." } }, "required": [ "field" ], "additionalProperties": false, "description": "Sort order for the results. Defaults to updated_at descending, with id as a tie-breaker." }, "limit": { "type": "integer", "minimum": 1, "default": 100, "description": "Maximum number of results to return in this page. Continue with next_cursor when returned." }, "cursor": { "type": "string", "description": "The `next_cursor` of the previous page." } }, "additionalProperties": false, "examples": [ { "limit": 10 } ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:SalesPipeline record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "name": { "type": "string", "description": "Name of the sales pipeline." }, "stages": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable stage ID referenced by deals. Keep it when changing the label." }, "label": { "type": "string", "description": "Human-readable stage name." }, "kind": { "type": "string", "enum": [ "open", "won", "lost" ], "description": "Whether this stage is open, won or lost." }, "probability": { "type": "number", "description": "Integer percentage from 0 to 100 used for weighted sales value." }, "tone": { "type": "string", "enum": [ "gray", "blue", "violet", "peach", "soon", "accent", "warn" ], "description": "Display color token for the stage." } }, "required": [ "id", "label", "kind" ], "additionalProperties": false }, "description": "Sales stages in funnel order. Keep stage IDs stable: deals refer to them. Exactly one won and one lost stage appear last; probability is an integer percentage from 0 to 100 for weighted sales value." }, "is_default": { "type": "boolean", "description": "Whether this is the workspace's default sales pipeline." } }, "required": [ "name" ], "additionalProperties": false, "description": "The record's fields.", "title": "SalesPipeline" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "title": "SalesPipelineRecord" }, "description": "Records visible under the credential's grants and the selected data scope, matching the requested filters. Pass next_cursor as cursor to continue when a next cursor is returned." }, "next_cursor": { "type": "string", "description": "Pass this value as cursor to continue with the same filters, sort and credential. Omitted when there are no more results." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "id": "e_salespipeline_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "Sales pipeline", "is_default": true, "stages": [ { "id": "lead", "label": "Lead", "kind": "open", "probability": 10 }, { "id": "won", "label": "Won", "kind": "won", "probability": 100 }, { "id": "lost", "label": "Lost", "kind": "lost", "probability": 0 } ] } } ] } ] } ``` --- # Create sales pipeline Create a sales pipeline and return the saved record. POST https://api.brigg.app/v1/operations/customers.CreateSalesPipeline ## Access & visibility Allow `customers.CreateSalesPipeline` on your API key. Resource read permissions: `core:SalesPipeline`. Resource write permissions: `core:SalesPipeline`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `data` | [SalesPipeline](#salespipeline-request-data) | Yes | The record's fields. | | `private` | boolean | No | Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance. | ### SalesPipeline · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Name of the sales pipeline. | | `stages` | array of [object](#request-data-stages) | No | Sales stages in funnel order. Keep stage IDs stable: deals refer to them. Exactly one won and one lost stage appear last; probability is an integer percentage from 0 to 100 for weighted sales value. | | `is_default` | boolean | No | Whether this is the workspace's default sales pipeline. | ### request.data.stages[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable stage ID referenced by deals. Keep it when changing the label. | | `label` | string | Yes | Human-readable stage name. | | `kind` | string | Yes | Whether this stage is open, won or lost. Allowed: `"open"`, `"won"`, `"lost"`. | | `probability` | number | No | Integer percentage from 0 to 100 used for weighted sales value. | | `tone` | string | No | Display color token for the stage. Allowed: `"gray"`, `"blue"`, `"violet"`, `"peach"`, `"soon"`, `"accent"`, `"warn"`. | ## Choose ownership deliberately Omitting `private`, or setting it to false, creates a workspace-shared record. Set `private: true` to create a record owned by the approved acting member. Private records require member delegation; a workspace-only credential cannot own a personal record. The credential’s exact resource grants authorize the write; private ownership and project membership remain enforced. A create is a new record, not an upsert. Reuse the same idempotency key only for retries of that logical creation. For recurring synchronization, use the resource’s upsert operation when available: it matches a permanent external reference. Otherwise keep the returned record ID and use the corresponding update operation for subsequent changes. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [SalesPipelineRecord](#salespipelinerecord-response-item) | Yes | The requested record, including its metadata and data fields. | ### SalesPipelineRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:SalesPipeline record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [SalesPipeline](#salespipeline-response-item-data) | Yes | The record's fields. | ### SalesPipeline · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Name of the sales pipeline. | | `stages` | array of [object](#response-item-data-stages) | No | Sales stages in funnel order. Keep stage IDs stable: deals refer to them. Exactly one won and one lost stage appear last; probability is an integer percentage from 0 to 100 for weighted sales value. | | `is_default` | boolean | No | Whether this is the workspace's default sales pipeline. | ### response.item.data.stages[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable stage ID referenced by deals. Keep it when changing the label. | | `label` | string | Yes | Human-readable stage name. | | `kind` | string | Yes | Whether this stage is open, won or lost. Allowed: `"open"`, `"won"`, `"lost"`. | | `probability` | number | No | Integer percentage from 0 to 100 used for weighted sales value. | | `tone` | string | No | Display color token for the stage. Allowed: `"gray"`, `"blue"`, `"violet"`, `"peach"`, `"soon"`, `"accent"`, `"warn"`. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List sales pipelines](/developers/reference/customers/ListSalesPipelines) - [Get sales pipeline](/developers/reference/customers/GetSalesPipeline) - [Upsert sales pipeline](/developers/reference/customers/UpsertSalesPipeline) - [Update sales pipeline](/developers/reference/customers/UpdateSalesPipeline) - [Delete sales pipeline](/developers/reference/customers/DeleteSalesPipeline) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.CreateSalesPipeline' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "data": { "name": "Sales pipeline", "is_default": true, "stages": [ { "id": "lead", "label": "Lead", "kind": "open", "probability": 10 }, { "id": "won", "label": "Won", "kind": "won", "probability": 100 }, { "id": "lost", "label": "Lost", "kind": "lost", "probability": 0 } ] } }' ``` #### TypeScript ```typescript 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/customers.CreateSalesPipeline", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "data": { "name": "Sales pipeline", "is_default": true, "stages": [ { "id": "lead", "label": "Lead", "kind": "open", "probability": 10 }, { "id": "won", "label": "Won", "kind": "won", "probability": 100 }, { "id": "lost", "label": "Lost", "kind": "lost", "probability": 0 } ] } }), }); 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 = { "data": { "name": "Sales pipeline", "is_default": True, "stages": [ { "id": "lead", "label": "Lead", "kind": "open", "probability": 10 }, { "id": "won", "label": "Won", "kind": "won", "probability": 100 }, { "id": "lost", "label": "Lost", "kind": "lost", "probability": 0 } ] } } request = Request( "https://api.brigg.app/v1/operations/customers.CreateSalesPipeline", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_salespipeline_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "Sales pipeline", "is_default": true, "stages": [ { "id": "lead", "label": "Lead", "kind": "open", "probability": 10 }, { "id": "won", "label": "Won", "kind": "won", "probability": 100 }, { "id": "lost", "label": "Lost", "kind": "lost", "probability": 0 } ] } } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "data": { "type": "object", "properties": { "name": { "type": "string", "description": "Name of the sales pipeline." }, "stages": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable stage ID referenced by deals. Keep it when changing the label." }, "label": { "type": "string", "description": "Human-readable stage name." }, "kind": { "type": "string", "enum": [ "open", "won", "lost" ], "description": "Whether this stage is open, won or lost." }, "probability": { "type": "number", "description": "Integer percentage from 0 to 100 used for weighted sales value." }, "tone": { "type": "string", "enum": [ "gray", "blue", "violet", "peach", "soon", "accent", "warn" ], "description": "Display color token for the stage." } }, "required": [ "id", "label", "kind" ], "additionalProperties": false }, "description": "Sales stages in funnel order. Keep stage IDs stable: deals refer to them. Exactly one won and one lost stage appear last; probability is an integer percentage from 0 to 100 for weighted sales value." }, "is_default": { "type": "boolean", "description": "Whether this is the workspace's default sales pipeline." } }, "required": [ "name" ], "additionalProperties": false, "description": "The record's fields.", "title": "SalesPipeline" }, "private": { "type": "boolean", "description": "Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance." } }, "required": [ "data" ], "additionalProperties": false, "examples": [ { "data": { "name": "Sales pipeline", "is_default": true, "stages": [ { "id": "lead", "label": "Lead", "kind": "open", "probability": 10 }, { "id": "won", "label": "Won", "kind": "won", "probability": 100 }, { "id": "lost", "label": "Lost", "kind": "lost", "probability": 0 } ] } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:SalesPipeline record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "name": { "type": "string", "description": "Name of the sales pipeline." }, "stages": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable stage ID referenced by deals. Keep it when changing the label." }, "label": { "type": "string", "description": "Human-readable stage name." }, "kind": { "type": "string", "enum": [ "open", "won", "lost" ], "description": "Whether this stage is open, won or lost." }, "probability": { "type": "number", "description": "Integer percentage from 0 to 100 used for weighted sales value." }, "tone": { "type": "string", "enum": [ "gray", "blue", "violet", "peach", "soon", "accent", "warn" ], "description": "Display color token for the stage." } }, "required": [ "id", "label", "kind" ], "additionalProperties": false }, "description": "Sales stages in funnel order. Keep stage IDs stable: deals refer to them. Exactly one won and one lost stage appear last; probability is an integer percentage from 0 to 100 for weighted sales value." }, "is_default": { "type": "boolean", "description": "Whether this is the workspace's default sales pipeline." } }, "required": [ "name" ], "additionalProperties": false, "description": "The record's fields.", "title": "SalesPipeline" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "SalesPipelineRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_salespipeline_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "Sales pipeline", "is_default": true, "stages": [ { "id": "lead", "label": "Lead", "kind": "open", "probability": 10 }, { "id": "won", "label": "Won", "kind": "won", "probability": 100 }, { "id": "lost", "label": "Lost", "kind": "lost", "probability": 0 } ] } } } ] } ``` --- # Delete sales pipeline Delete a sales pipeline by ID. Repeating a deletion returns already_deleted. POST https://api.brigg.app/v1/operations/customers.DeleteSalesPipeline ## Access & visibility Allow `customers.DeleteSalesPipeline` on your API key. Resource read permissions: `core:SalesPipeline`. Resource write permissions: `core:SalesPipeline`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:SalesPipeline` record. Find it with [customers.ListSalesPipelines](/developers/reference/customers/ListSalesPipelines). Use the record's top-level `id`, not a business field or account ID. | | `expected` | [object](#request-expected) | No | Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {"$absent":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource. | ### request.expected | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string or [object](#request-expected-name) | No | Commit only if the previous name value matches; use $absent to require that this field is missing. | | `stages` | array of [object](#request-expected-stages) or [object](#request-expected-stages) | No | Commit only if the previous stages value matches; use $absent to require that this field is missing. | | `is_default` | boolean or [object](#request-expected-is-default) | No | Commit only if the previous is_default value matches; use $absent to require that this field is missing. | ### request.expected.name | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.stages | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.stages[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable stage ID referenced by deals. Keep it when changing the label. | | `label` | string | Yes | Human-readable stage name. | | `kind` | string | Yes | Whether this stage is open, won or lost. Allowed: `"open"`, `"won"`, `"lost"`. | | `probability` | number | No | Integer percentage from 0 to 100 used for weighted sales value. | | `tone` | string | No | Display color token for the stage. Allowed: `"gray"`, `"blue"`, `"violet"`, `"peach"`, `"soon"`, `"accent"`, `"warn"`. | ### request.expected.is_default | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ## Deletion and retries A successful response reports whether this call removed the record or it was already absent. Check `cascaded` for dependent record IDs returned by the operation. Retrying the same action uses the original idempotency key. A successful deletion is not an archive you can restore through this operation. To avoid deleting a record someone has changed, read it first and put the relevant prior business values in `expected`. Keys are relative to `data`, not prefixed with `data.`. Use {"$absent": true} to require a missing field. A mismatch returns 409 conflict; read again and decide whether deletion is still appropriate. A revised action needs a new idempotency key. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `deleted` | string | Yes | deleted when this request removed the record; already_deleted when it was already absent. Allowed: `"deleted"`, `"already_deleted"`. | | `cascaded` | array of string | No | IDs of dependent records deleted with this 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `conflict` | A supplied expected value no longer matches. Read the record again before deciding whether to retry. | ## Next steps - [List sales pipelines](/developers/reference/customers/ListSalesPipelines) - [Get sales pipeline](/developers/reference/customers/GetSalesPipeline) - [Create sales pipeline](/developers/reference/customers/CreateSalesPipeline) - [Upsert sales pipeline](/developers/reference/customers/UpsertSalesPipeline) - [Update sales pipeline](/developers/reference/customers/UpdateSalesPipeline) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.DeleteSalesPipeline' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_salespipeline_example" }' ``` #### TypeScript ```typescript 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/customers.DeleteSalesPipeline", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_salespipeline_example" }), }); 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_salespipeline_example" } request = Request( "https://api.brigg.app/v1/operations/customers.DeleteSalesPipeline", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "deleted": "deleted" } ``` ### Delete only if unchanged Use a value you actually read. A concurrent change refuses the write with 409 conflict. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.DeleteSalesPipeline' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_salespipeline_example", "expected": { "name": "Sales pipeline" } }' ``` #### TypeScript ```typescript 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/customers.DeleteSalesPipeline", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_salespipeline_example", "expected": { "name": "Sales pipeline" } }), }); 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_salespipeline_example", "expected": { "name": "Sales pipeline" } } request = Request( "https://api.brigg.app/v1/operations/customers.DeleteSalesPipeline", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "deleted": "deleted" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:SalesPipeline` record. Find it with [customers.ListSalesPipelines](/developers/reference/customers/ListSalesPipelines). Use the record's top-level `id`, not a business field or account ID." }, "expected": { "type": "object", "description": "Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {\"$absent\":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource.", "additionalProperties": false, "properties": { "name": { "description": "Commit only if the previous name value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Name of the sales pipeline." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "stages": { "description": "Commit only if the previous stages value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable stage ID referenced by deals. Keep it when changing the label." }, "label": { "type": "string", "description": "Human-readable stage name." }, "kind": { "type": "string", "enum": [ "open", "won", "lost" ], "description": "Whether this stage is open, won or lost." }, "probability": { "type": "number", "description": "Integer percentage from 0 to 100 used for weighted sales value." }, "tone": { "type": "string", "enum": [ "gray", "blue", "violet", "peach", "soon", "accent", "warn" ], "description": "Display color token for the stage." } }, "required": [ "id", "label", "kind" ], "additionalProperties": false }, "description": "Sales stages in funnel order. Keep stage IDs stable: deals refer to them. Exactly one won and one lost stage appear last; probability is an integer percentage from 0 to 100 for weighted sales value." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "is_default": { "description": "Commit only if the previous is_default value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "boolean", "description": "Whether this is the workspace's default sales pipeline." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] } } } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_salespipeline_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "deleted": { "type": "string", "enum": [ "deleted", "already_deleted" ], "description": "deleted when this request removed the record; already_deleted when it was already absent." }, "cascaded": { "type": "array", "items": { "type": "string" }, "description": "IDs of dependent records deleted with this record." } }, "required": [ "deleted" ], "additionalProperties": false, "examples": [ { "deleted": "deleted" } ] } ``` --- # Update sales pipeline Update a sales pipeline by ID. Omitted fields stay unchanged; use unset to remove fields and expected to prevent overwriting a concurrent change. POST https://api.brigg.app/v1/operations/customers.UpdateSalesPipeline ## Access & visibility Allow `customers.UpdateSalesPipeline` on your API key. Resource read permissions: `core:SalesPipeline`. Resource write permissions: `core:SalesPipeline`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:SalesPipeline` record. Find it with [customers.ListSalesPipelines](/developers/reference/customers/ListSalesPipelines). Use the record's top-level `id`, not a business field or account ID. | | `data` | [SalesPipeline](#salespipeline-request-data) | No | The fields to set. | | `unset` | array of string | No | Keys of `data` to remove. Each item: `"name"`, `"stages"`, `"is_default"`. | | `expected` | [object](#request-expected) | No | Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {"$absent":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource. | ### SalesPipeline · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | No | Name of the sales pipeline. | | `stages` | array of [object](#request-data-stages) | No | Sales stages in funnel order. Keep stage IDs stable: deals refer to them. Exactly one won and one lost stage appear last; probability is an integer percentage from 0 to 100 for weighted sales value. | | `is_default` | boolean | No | Whether this is the workspace's default sales pipeline. | ### request.data.stages[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable stage ID referenced by deals. Keep it when changing the label. | | `label` | string | Yes | Human-readable stage name. | | `kind` | string | Yes | Whether this stage is open, won or lost. Allowed: `"open"`, `"won"`, `"lost"`. | | `probability` | number | No | Integer percentage from 0 to 100 used for weighted sales value. | | `tone` | string | No | Display color token for the stage. Allowed: `"gray"`, `"blue"`, `"violet"`, `"peach"`, `"soon"`, `"accent"`, `"warn"`. | ### request.expected | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string or [object](#request-expected-name) | No | Commit only if the previous name value matches; use $absent to require that this field is missing. | | `stages` | array of [object](#request-expected-stages) or [object](#request-expected-stages) | No | Commit only if the previous stages value matches; use $absent to require that this field is missing. | | `is_default` | boolean or [object](#request-expected-is-default) | No | Commit only if the previous is_default value matches; use $absent to require that this field is missing. | ### request.expected.name | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.stages | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.stages[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable stage ID referenced by deals. Keep it when changing the label. | | `label` | string | Yes | Human-readable stage name. | | `kind` | string | Yes | Whether this stage is open, won or lost. Allowed: `"open"`, `"won"`, `"lost"`. | | `probability` | number | No | Integer percentage from 0 to 100 used for weighted sales value. | | `tone` | string | No | Display color token for the stage. Allowed: `"gray"`, `"blue"`, `"violet"`, `"peach"`, `"soon"`, `"accent"`, `"warn"`. | ### request.expected.is_default | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ## Update without losing changes Send only the business fields you want to change in `data`; omitted fields stay unchanged. Use `unset` to remove an optional field. Setting a field to null is a different action and is allowed only when its schema permits null. Use `expected` for a conditional update: supply the values you last read for the fields whose concurrent changes would matter. `{"$absent": true}` expects a missing field. A conflict means you must read the record again and decide how to reconcile the change. Keep the same idempotency key when retrying the original action; use a new key for a revised action. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [SalesPipelineRecord](#salespipelinerecord-response-item) | Yes | The requested record, including its metadata and data fields. | ### SalesPipelineRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:SalesPipeline record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [SalesPipeline](#salespipeline-response-item-data) | Yes | The record's fields. | ### SalesPipeline · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Name of the sales pipeline. | | `stages` | array of [object](#response-item-data-stages) | No | Sales stages in funnel order. Keep stage IDs stable: deals refer to them. Exactly one won and one lost stage appear last; probability is an integer percentage from 0 to 100 for weighted sales value. | | `is_default` | boolean | No | Whether this is the workspace's default sales pipeline. | ### response.item.data.stages[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable stage ID referenced by deals. Keep it when changing the label. | | `label` | string | Yes | Human-readable stage name. | | `kind` | string | Yes | Whether this stage is open, won or lost. Allowed: `"open"`, `"won"`, `"lost"`. | | `probability` | number | No | Integer percentage from 0 to 100 used for weighted sales value. | | `tone` | string | No | Display color token for the stage. Allowed: `"gray"`, `"blue"`, `"violet"`, `"peach"`, `"soon"`, `"accent"`, `"warn"`. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `conflict` | A supplied expected value no longer matches. Read the record again before deciding whether to retry. | ## Next steps - [List sales pipelines](/developers/reference/customers/ListSalesPipelines) - [Get sales pipeline](/developers/reference/customers/GetSalesPipeline) - [Create sales pipeline](/developers/reference/customers/CreateSalesPipeline) - [Upsert sales pipeline](/developers/reference/customers/UpsertSalesPipeline) - [Delete sales pipeline](/developers/reference/customers/DeleteSalesPipeline) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.UpdateSalesPipeline' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_salespipeline_example", "data": { "name": "Customer sales" } }' ``` #### TypeScript ```typescript 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/customers.UpdateSalesPipeline", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_salespipeline_example", "data": { "name": "Customer sales" } }), }); 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_salespipeline_example", "data": { "name": "Customer sales" } } request = Request( "https://api.brigg.app/v1/operations/customers.UpdateSalesPipeline", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_salespipeline_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "Customer sales", "is_default": true, "stages": [ { "id": "lead", "label": "Lead", "kind": "open", "probability": 10 }, { "id": "won", "label": "Won", "kind": "won", "probability": 100 }, { "id": "lost", "label": "Lost", "kind": "lost", "probability": 0 } ] } } } ``` ### Update only if unchanged Use a value you actually read. A concurrent change refuses the write with 409 conflict. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.UpdateSalesPipeline' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_salespipeline_example", "data": { "name": "Customer sales" }, "expected": { "name": "Sales pipeline" } }' ``` #### TypeScript ```typescript 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/customers.UpdateSalesPipeline", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_salespipeline_example", "data": { "name": "Customer sales" }, "expected": { "name": "Sales pipeline" } }), }); 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_salespipeline_example", "data": { "name": "Customer sales" }, "expected": { "name": "Sales pipeline" } } request = Request( "https://api.brigg.app/v1/operations/customers.UpdateSalesPipeline", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_salespipeline_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "Customer sales", "is_default": true, "stages": [ { "id": "lead", "label": "Lead", "kind": "open", "probability": 10 }, { "id": "won", "label": "Won", "kind": "won", "probability": 100 }, { "id": "lost", "label": "Lost", "kind": "lost", "probability": 0 } ] } } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:SalesPipeline` record. Find it with [customers.ListSalesPipelines](/developers/reference/customers/ListSalesPipelines). Use the record's top-level `id`, not a business field or account ID." }, "data": { "type": "object", "properties": { "name": { "type": "string", "description": "Name of the sales pipeline." }, "stages": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable stage ID referenced by deals. Keep it when changing the label." }, "label": { "type": "string", "description": "Human-readable stage name." }, "kind": { "type": "string", "enum": [ "open", "won", "lost" ], "description": "Whether this stage is open, won or lost." }, "probability": { "type": "number", "description": "Integer percentage from 0 to 100 used for weighted sales value." }, "tone": { "type": "string", "enum": [ "gray", "blue", "violet", "peach", "soon", "accent", "warn" ], "description": "Display color token for the stage." } }, "required": [ "id", "label", "kind" ], "additionalProperties": false }, "description": "Sales stages in funnel order. Keep stage IDs stable: deals refer to them. Exactly one won and one lost stage appear last; probability is an integer percentage from 0 to 100 for weighted sales value." }, "is_default": { "type": "boolean", "description": "Whether this is the workspace's default sales pipeline." } }, "required": [], "additionalProperties": false, "description": "The fields to set.", "title": "SalesPipeline" }, "unset": { "type": "array", "items": { "type": "string", "enum": [ "name", "stages", "is_default" ] }, "description": "Keys of `data` to remove." }, "expected": { "type": "object", "description": "Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {\"$absent\":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource.", "additionalProperties": false, "properties": { "name": { "description": "Commit only if the previous name value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Name of the sales pipeline." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "stages": { "description": "Commit only if the previous stages value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable stage ID referenced by deals. Keep it when changing the label." }, "label": { "type": "string", "description": "Human-readable stage name." }, "kind": { "type": "string", "enum": [ "open", "won", "lost" ], "description": "Whether this stage is open, won or lost." }, "probability": { "type": "number", "description": "Integer percentage from 0 to 100 used for weighted sales value." }, "tone": { "type": "string", "enum": [ "gray", "blue", "violet", "peach", "soon", "accent", "warn" ], "description": "Display color token for the stage." } }, "required": [ "id", "label", "kind" ], "additionalProperties": false }, "description": "Sales stages in funnel order. Keep stage IDs stable: deals refer to them. Exactly one won and one lost stage appear last; probability is an integer percentage from 0 to 100 for weighted sales value." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "is_default": { "description": "Commit only if the previous is_default value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "boolean", "description": "Whether this is the workspace's default sales pipeline." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] } } } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_salespipeline_example", "data": { "name": "Customer sales" } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:SalesPipeline record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "name": { "type": "string", "description": "Name of the sales pipeline." }, "stages": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable stage ID referenced by deals. Keep it when changing the label." }, "label": { "type": "string", "description": "Human-readable stage name." }, "kind": { "type": "string", "enum": [ "open", "won", "lost" ], "description": "Whether this stage is open, won or lost." }, "probability": { "type": "number", "description": "Integer percentage from 0 to 100 used for weighted sales value." }, "tone": { "type": "string", "enum": [ "gray", "blue", "violet", "peach", "soon", "accent", "warn" ], "description": "Display color token for the stage." } }, "required": [ "id", "label", "kind" ], "additionalProperties": false }, "description": "Sales stages in funnel order. Keep stage IDs stable: deals refer to them. Exactly one won and one lost stage appear last; probability is an integer percentage from 0 to 100 for weighted sales value." }, "is_default": { "type": "boolean", "description": "Whether this is the workspace's default sales pipeline." } }, "required": [ "name" ], "additionalProperties": false, "description": "The record's fields.", "title": "SalesPipeline" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "SalesPipelineRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_salespipeline_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "Customer sales", "is_default": true, "stages": [ { "id": "lead", "label": "Lead", "kind": "open", "probability": 10 }, { "id": "won", "label": "Won", "kind": "won", "probability": 100 }, { "id": "lost", "label": "Lost", "kind": "lost", "probability": 0 } ] } } } ] } ``` --- # Upsert sales pipeline Create or update a sales pipeline by a permanent external reference. Matching is exact within the workspace, resource type and ownership scope. Supplied fields replace their values; omitted fields stay unchanged. Deleted records are not recreated. POST https://api.brigg.app/v1/operations/customers.UpsertSalesPipeline ## Access & visibility Allow `customers.UpsertSalesPipeline` on your API key. Resource read permissions: `core:SalesPipeline`. Resource write permissions: `core:SalesPipeline`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `data` | [SalesPipeline](#salespipeline-request-data) | Yes | The record's fields. | | `private` | boolean | No | Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance. | | `external_ref` | [object](#request-external-ref) | Yes | Permanent, case-sensitive source identity within this workspace, resource type and private/workspace scope. It is independent of API key rotation and retry receipt expiry. | ### SalesPipeline · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Name of the sales pipeline. | | `stages` | array of [object](#request-data-stages) | No | Sales stages in funnel order. Keep stage IDs stable: deals refer to them. Exactly one won and one lost stage appear last; probability is an integer percentage from 0 to 100 for weighted sales value. | | `is_default` | boolean | No | Whether this is the workspace's default sales pipeline. | ### request.data.stages[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable stage ID referenced by deals. Keep it when changing the label. | | `label` | string | Yes | Human-readable stage name. | | `kind` | string | Yes | Whether this stage is open, won or lost. Allowed: `"open"`, `"won"`, `"lost"`. | | `probability` | number | No | Integer percentage from 0 to 100 used for weighted sales value. | | `tone` | string | No | Display color token for the stage. Allowed: `"gray"`, `"blue"`, `"violet"`, `"peach"`, `"soon"`, `"accent"`, `"warn"`. | ### request.external_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `namespace` | string | Yes | A stable name for the source system, such as crm-production. At least 1 character. | | `id` | string | Yes | The record ID in that source system. At least 1 character. | ## Sync with a permanent external reference Choose a stable `external_ref.namespace` for your source system and put its record ID in `external_ref.id`. Matching is case-sensitive and scoped to this workspace, resource type and private/workspace ownership. The reference survives API key replacement and the 30-day retry receipt window. It does not match records by email or name. Send the required create fields each time. A missing reference creates a record; an existing reference updates only supplied fields and preserves everything else. `created` tells you which happened. Use the same idempotency key when retrying a lost response and a new key for a later source change. Concurrent calls cannot create duplicate records. A deleted or inaccessible match is refused; the operation does not restore it or make a replacement. Use the returned `item.id` with the regular update operation when you need `unset` or a conditional `expected` edit. Changing `private` chooses a different ownership scope; it does not transfer an existing record. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [SalesPipelineRecord](#salespipelinerecord-response-item) | Yes | The requested record, including its metadata and data fields. | | `created` | boolean | Yes | True when this external reference created a record; false when it matched an existing record. | ### SalesPipelineRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:SalesPipeline record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [SalesPipeline](#salespipeline-response-item-data) | Yes | The record's fields. | ### SalesPipeline · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Name of the sales pipeline. | | `stages` | array of [object](#response-item-data-stages) | No | Sales stages in funnel order. Keep stage IDs stable: deals refer to them. Exactly one won and one lost stage appear last; probability is an integer percentage from 0 to 100 for weighted sales value. | | `is_default` | boolean | No | Whether this is the workspace's default sales pipeline. | ### response.item.data.stages[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable stage ID referenced by deals. Keep it when changing the label. | | `label` | string | Yes | Human-readable stage name. | | `kind` | string | Yes | Whether this stage is open, won or lost. Allowed: `"open"`, `"won"`, `"lost"`. | | `probability` | number | No | Integer percentage from 0 to 100 used for weighted sales value. | | `tone` | string | No | Display color token for the stage. Allowed: `"gray"`, `"blue"`, `"violet"`, `"peach"`, `"soon"`, `"accent"`, `"warn"`. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List sales pipelines](/developers/reference/customers/ListSalesPipelines) - [Get sales pipeline](/developers/reference/customers/GetSalesPipeline) - [Create sales pipeline](/developers/reference/customers/CreateSalesPipeline) - [Update sales pipeline](/developers/reference/customers/UpdateSalesPipeline) - [Delete sales pipeline](/developers/reference/customers/DeleteSalesPipeline) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### First sync Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.UpsertSalesPipeline' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "name": "Sales pipeline", "is_default": true, "stages": [ { "id": "lead", "label": "Lead", "kind": "open", "probability": 10 }, { "id": "won", "label": "Won", "kind": "won", "probability": 100 }, { "id": "lost", "label": "Lost", "kind": "lost", "probability": 0 } ] } }' ``` #### TypeScript ```typescript 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/customers.UpsertSalesPipeline", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "name": "Sales pipeline", "is_default": true, "stages": [ { "id": "lead", "label": "Lead", "kind": "open", "probability": 10 }, { "id": "won", "label": "Won", "kind": "won", "probability": 100 }, { "id": "lost", "label": "Lost", "kind": "lost", "probability": 0 } ] } }), }); 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 = { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "name": "Sales pipeline", "is_default": True, "stages": [ { "id": "lead", "label": "Lead", "kind": "open", "probability": 10 }, { "id": "won", "label": "Won", "kind": "won", "probability": 100 }, { "id": "lost", "label": "Lost", "kind": "lost", "probability": 0 } ] } } request = Request( "https://api.brigg.app/v1/operations/customers.UpsertSalesPipeline", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_salespipeline_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "Sales pipeline", "is_default": true, "stages": [ { "id": "lead", "label": "Lead", "kind": "open", "probability": 10 }, { "id": "won", "label": "Won", "kind": "won", "probability": 100 }, { "id": "lost", "label": "Lost", "kind": "lost", "probability": 0 } ] } }, "created": true } ``` ### Later sync The same external reference returns the same record ID. Use a new idempotency key for a later source change. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.UpsertSalesPipeline' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "name": "Sales pipeline", "is_default": true, "stages": [ { "id": "lead", "label": "Lead", "kind": "open", "probability": 10 }, { "id": "won", "label": "Won", "kind": "won", "probability": 100 }, { "id": "lost", "label": "Lost", "kind": "lost", "probability": 0 } ] } }' ``` #### TypeScript ```typescript 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/customers.UpsertSalesPipeline", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "name": "Sales pipeline", "is_default": true, "stages": [ { "id": "lead", "label": "Lead", "kind": "open", "probability": 10 }, { "id": "won", "label": "Won", "kind": "won", "probability": 100 }, { "id": "lost", "label": "Lost", "kind": "lost", "probability": 0 } ] } }), }); 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 = { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "name": "Sales pipeline", "is_default": True, "stages": [ { "id": "lead", "label": "Lead", "kind": "open", "probability": 10 }, { "id": "won", "label": "Won", "kind": "won", "probability": 100 }, { "id": "lost", "label": "Lost", "kind": "lost", "probability": 0 } ] } } request = Request( "https://api.brigg.app/v1/operations/customers.UpsertSalesPipeline", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_salespipeline_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "Sales pipeline", "is_default": true, "stages": [ { "id": "lead", "label": "Lead", "kind": "open", "probability": 10 }, { "id": "won", "label": "Won", "kind": "won", "probability": 100 }, { "id": "lost", "label": "Lost", "kind": "lost", "probability": 0 } ] } }, "created": false } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "data": { "type": "object", "properties": { "name": { "type": "string", "description": "Name of the sales pipeline." }, "stages": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable stage ID referenced by deals. Keep it when changing the label." }, "label": { "type": "string", "description": "Human-readable stage name." }, "kind": { "type": "string", "enum": [ "open", "won", "lost" ], "description": "Whether this stage is open, won or lost." }, "probability": { "type": "number", "description": "Integer percentage from 0 to 100 used for weighted sales value." }, "tone": { "type": "string", "enum": [ "gray", "blue", "violet", "peach", "soon", "accent", "warn" ], "description": "Display color token for the stage." } }, "required": [ "id", "label", "kind" ], "additionalProperties": false }, "description": "Sales stages in funnel order. Keep stage IDs stable: deals refer to them. Exactly one won and one lost stage appear last; probability is an integer percentage from 0 to 100 for weighted sales value." }, "is_default": { "type": "boolean", "description": "Whether this is the workspace's default sales pipeline." } }, "required": [ "name" ], "additionalProperties": false, "description": "The record's fields.", "title": "SalesPipeline" }, "private": { "type": "boolean", "description": "Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance." }, "external_ref": { "type": "object", "description": "Permanent, case-sensitive source identity within this workspace, resource type and private/workspace scope. It is independent of API key rotation and retry receipt expiry.", "properties": { "namespace": { "type": "string", "minLength": 1, "description": "A stable name for the source system, such as crm-production." }, "id": { "type": "string", "minLength": 1, "description": "The record ID in that source system." } }, "required": [ "namespace", "id" ], "additionalProperties": false } }, "required": [ "external_ref", "data" ], "additionalProperties": false, "examples": [ { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "name": "Sales pipeline", "is_default": true, "stages": [ { "id": "lead", "label": "Lead", "kind": "open", "probability": 10 }, { "id": "won", "label": "Won", "kind": "won", "probability": 100 }, { "id": "lost", "label": "Lost", "kind": "lost", "probability": 0 } ] } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:SalesPipeline record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "name": { "type": "string", "description": "Name of the sales pipeline." }, "stages": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable stage ID referenced by deals. Keep it when changing the label." }, "label": { "type": "string", "description": "Human-readable stage name." }, "kind": { "type": "string", "enum": [ "open", "won", "lost" ], "description": "Whether this stage is open, won or lost." }, "probability": { "type": "number", "description": "Integer percentage from 0 to 100 used for weighted sales value." }, "tone": { "type": "string", "enum": [ "gray", "blue", "violet", "peach", "soon", "accent", "warn" ], "description": "Display color token for the stage." } }, "required": [ "id", "label", "kind" ], "additionalProperties": false }, "description": "Sales stages in funnel order. Keep stage IDs stable: deals refer to them. Exactly one won and one lost stage appear last; probability is an integer percentage from 0 to 100 for weighted sales value." }, "is_default": { "type": "boolean", "description": "Whether this is the workspace's default sales pipeline." } }, "required": [ "name" ], "additionalProperties": false, "description": "The record's fields.", "title": "SalesPipeline" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "SalesPipelineRecord" }, "created": { "type": "boolean", "description": "True when this external reference created a record; false when it matched an existing record." } }, "required": [ "item", "created" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_salespipeline_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "Sales pipeline", "is_default": true, "stages": [ { "id": "lead", "label": "Lead", "kind": "open", "probability": 10 }, { "id": "won", "label": "Won", "kind": "won", "probability": 100 }, { "id": "lost", "label": "Lost", "kind": "lost", "probability": 0 } ] } }, "created": true } ] } ``` --- # List tags List the workspace's available tag keys and labels, optionally for one record field. Records store tag keys, not labels. POST https://api.brigg.app/v1/operations/customers.ListTags ## Access & visibility Allow `customers.ListTags` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `vocabulary_id` | string | No | Select the vocabulary for the record's resource_type and field. Use vocabulary_id, not its display label. [customers.ListTagVocabularies](/developers/reference/customers/ListTagVocabularies). At least 1 character. At most 200 characters. | ## Use stored keys, not labels 1. [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) and select the record's `resource_type` and `field`. 2. [List tags](/developers/reference/customers/ListTags) with its `vocabulary_id`. 3. Store the tag's `key` in the record field; use `label` and `color` only for display. Renaming a label does not change its stored key. System tags are protected from update and deletion. Deleting a user tag also removes that key from affected records; `entries_stripped` reports how many records changed. Removing one record's tag assignment instead uses that record's update operation. ## Response Returns **200 OK** with a JSON body. This operation has no continuation cursor. An empty `items` array means no matching visible results were returned. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [Tag](#tag-response-items) | Yes | Tags in the selected vocabulary. This operation has no cursor pagination. | ### Tag · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `vocabulary_id` | string | Yes | Vocabulary containing this tag. The pair vocabulary_id and key identifies a tag. | | `key` | string | Yes | Stable stored value used when assigning the tag to a record; do not send its display label instead. | | `label` | string or null | Yes | Human-readable tag name, which can change without changing its key. | | `color` | string or null | Yes | Display color assigned to the tag, or null when no color was selected. | | `system` | boolean | Yes | Whether this is a built-in tag protected from editing and deletion. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) - [Create tag](/developers/reference/customers/CreateTag) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.ListTags' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{}' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.ListTags", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/customers.ListTags", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "vocabulary_id": "core:Company.tags", "key": "priority", "label": "Priority", "color": null, "system": false } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "vocabulary_id": { "type": "string", "minLength": 1, "maxLength": 200, "description": "Select the vocabulary for the record's resource_type and field. Use vocabulary_id, not its display label. [customers.ListTagVocabularies](/developers/reference/customers/ListTagVocabularies)." } }, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "vocabulary_id": { "type": "string", "description": "Vocabulary containing this tag. The pair vocabulary_id and key identifies a tag.", "examples": [ "core:Company.tags" ] }, "key": { "type": "string", "description": "Stable stored value used when assigning the tag to a record; do not send its display label instead.", "examples": [ "priority" ] }, "label": { "type": [ "string", "null" ], "description": "Human-readable tag name, which can change without changing its key.", "examples": [ "Priority" ] }, "color": { "type": [ "string", "null" ], "description": "Display color assigned to the tag, or null when no color was selected.", "examples": [ null ] }, "system": { "type": "boolean", "description": "Whether this is a built-in tag protected from editing and deletion.", "examples": [ false ] } }, "required": [ "vocabulary_id", "key", "label", "color", "system" ], "additionalProperties": false, "title": "Tag" }, "description": "Tags in the selected vocabulary. This operation has no cursor pagination." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "vocabulary_id": "core:Company.tags", "key": "priority", "label": "Priority", "color": null, "system": false } ] } ] } ``` --- # List tag vocabularies Discover the tag vocabularies for record types this credential can read. Each vocabulary belongs to one resource type and field. Use its ID to list or manage tags. POST https://api.brigg.app/v1/operations/customers.ListTagVocabularies ## Access & visibility Allow `customers.ListTagVocabularies` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/permissions) ## Request No parameters. Send an empty JSON object (`{}`). ## Use stored keys, not labels 1. [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) and select the record's `resource_type` and `field`. 2. [List tags](/developers/reference/customers/ListTags) with its `vocabulary_id`. 3. Store the tag's `key` in the record field; use `label` and `color` only for display. Renaming a label does not change its stored key. System tags are protected from update and deletion. Deleting a user tag also removes that key from affected records; `entries_stripped` reports how many records changed. Removing one record's tag assignment instead uses that record's update operation. ## Response Returns **200 OK** with a JSON body. This operation has no continuation cursor. An empty `items` array means no matching visible results were returned. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [Tag vocabulary](#tag-vocabulary-response-items) | Yes | Tag vocabularies available in the workspace. This operation has no cursor pagination. | ### Tag vocabulary · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `vocabulary_id` | string | Yes | Stable vocabulary ID. Pass it to ListTags to discover its allowed tag keys. | | `resource_type` | string | Yes | Record type whose field uses this vocabulary, for example core:Company. | | `field` | string | Yes | Business field on that record type that stores the tag keys. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [List tags](/developers/reference/customers/ListTags) - [Create tag](/developers/reference/customers/CreateTag) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.ListTagVocabularies' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{}' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/customers.ListTagVocabularies", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/customers.ListTagVocabularies", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "vocabulary_id": "core:Company.tags", "resource_type": "core:Company", "field": "tags" } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": {}, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "vocabulary_id": { "type": "string", "description": "Stable vocabulary ID. Pass it to ListTags to discover its allowed tag keys.", "examples": [ "core:Company.tags" ] }, "resource_type": { "type": "string", "description": "Record type whose field uses this vocabulary, for example core:Company.", "examples": [ "core:Company" ] }, "field": { "type": "string", "description": "Business field on that record type that stores the tag keys.", "examples": [ "tags" ] } }, "required": [ "vocabulary_id", "resource_type", "field" ], "additionalProperties": false, "title": "Tag vocabulary" }, "description": "Tag vocabularies available in the workspace. This operation has no cursor pagination." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "vocabulary_id": "core:Company.tags", "resource_type": "core:Company", "field": "tags" } ] } ] } ``` --- # Create tag Create a reusable tag for a record type. Its stable key is derived from the label; an existing key returns created: false. POST https://api.brigg.app/v1/operations/customers.CreateTag ## Access & visibility Allow `customers.CreateTag` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `vocabulary_id` | string | Yes | Select the vocabulary for the record's resource_type and field. Use vocabulary_id, not its display label. [customers.ListTagVocabularies](/developers/reference/customers/ListTagVocabularies). At least 1 character. At most 200 characters. | | `label` | string | Yes | The label people see, in their language ('Vestlandet', 'VIP'). The stable key is slugged from it and returned — write THAT key onto entries, never the label. At least 1 character. At most 80 characters. | | `color` | string or null | No | A colour token, or null for none. | ## Use stored keys, not labels 1. [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) and select the record's `resource_type` and `field`. 2. [List tags](/developers/reference/customers/ListTags) with its `vocabulary_id`. 3. Store the tag's `key` in the record field; use `label` and `color` only for display. Renaming a label does not change its stored key. System tags are protected from update and deletion. Deleting a user tag also removes that key from affected records; `entries_stripped` reports how many records changed. Removing one record's tag assignment instead uses that record's update operation. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `tag` | [Tag](#tag-response-tag) | Yes | Created tag, identified by its vocabulary and stable key. The label is for display. | | `created` | boolean | Yes | Records newly created by the import, or whether this reusable item was newly created. | ### Tag · response.tag | Field | Type | Required | Description | | --- | --- | --- | --- | | `vocabulary_id` | string | Yes | Vocabulary identifier. | | `key` | string | Yes | Stable key identifying this option within its collection; distinct from its display label. | | `label` | null or string | Yes | Human-readable label shown for this item; use its ID or key in API calls. | | `color` | null or string | Yes | Display color assigned to this item. | | `system` | boolean | Yes | Whether this item is managed by Brigg rather than user-created. Allowed: `false`, `true`. | | `source` | string | Yes | Origin or source attribution recorded for this item. | | `created_at` | number | Yes | Creation time in Unix milliseconds. | | `updated_at` | number | Yes | Last update time in Unix milliseconds. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) - [List tags](/developers/reference/customers/ListTags) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.CreateTag' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "vocabulary_id": "e_example", "label": "Priority" }' ``` #### TypeScript ```typescript 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/customers.CreateTag", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "vocabulary_id": "e_example", "label": "Priority" }), }); 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 = { "vocabulary_id": "e_example", "label": "Priority" } request = Request( "https://api.brigg.app/v1/operations/customers.CreateTag", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "tag": { "vocabulary_id": "e_example", "key": "priority", "label": "Priority", "color": "green", "system": false, "source": "user", "created_at": 1794301200000, "updated_at": 1794301200000 }, "created": false } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "vocabulary_id": { "type": "string", "minLength": 1, "maxLength": 200, "description": "Select the vocabulary for the record's resource_type and field. Use vocabulary_id, not its display label. [customers.ListTagVocabularies](/developers/reference/customers/ListTagVocabularies)." }, "label": { "type": "string", "minLength": 1, "maxLength": 80, "description": "The label people see, in their language ('Vestlandet', 'VIP'). The stable key is slugged from it and returned — write THAT key onto entries, never the label." }, "color": { "anyOf": [ { "type": "string", "maxLength": 32 }, { "type": "null" } ], "description": "A colour token, or null for none." } }, "required": [ "vocabulary_id", "label" ], "additionalProperties": false, "examples": [ { "vocabulary_id": "e_example", "label": "Priority" } ] } ``` ```json-schema-response { "type": "object", "properties": { "tag": { "description": "Created tag, identified by its vocabulary and stable key. The label is for display.", "title": "Tag", "type": "object", "properties": { "vocabulary_id": { "type": "string", "description": "Vocabulary identifier." }, "key": { "type": "string", "description": "Stable key identifying this option within its collection; distinct from its display label." }, "label": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Human-readable label shown for this item; use its ID or key in API calls." }, "color": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Display color assigned to this item." }, "system": { "type": "boolean", "enum": [ false, true ], "description": "Whether this item is managed by Brigg rather than user-created." }, "source": { "type": "string", "description": "Origin or source attribution recorded for this item." }, "created_at": { "type": "number", "description": "Creation time in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Last update time in Unix milliseconds." } }, "required": [ "vocabulary_id", "key", "label", "color", "system", "source", "created_at", "updated_at" ], "additionalProperties": false }, "created": { "type": "boolean", "description": "Records newly created by the import, or whether this reusable item was newly created." } }, "required": [ "tag", "created" ], "additionalProperties": false, "examples": [ { "tag": { "vocabulary_id": "e_example", "key": "priority", "label": "Priority", "color": "green", "system": false, "source": "user", "created_at": 1794301200000, "updated_at": 1794301200000 }, "created": false } ] } ``` --- # Delete tag Delete a tag and remove it from records of its type. Returns the number of affected records. System tags cannot be deleted. POST https://api.brigg.app/v1/operations/customers.DeleteTag ## Access & visibility Allow `customers.DeleteTag` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `vocabulary_id` | string | Yes | Select the vocabulary for the record's resource_type and field. Use vocabulary_id, not its display label. [customers.ListTagVocabularies](/developers/reference/customers/ListTagVocabularies). At least 1 character. At most 200 characters. | | `key` | string | Yes | The tag's stable key. At least 1 character. At most 80 characters. | ## Use stored keys, not labels 1. [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) and select the record's `resource_type` and `field`. 2. [List tags](/developers/reference/customers/ListTags) with its `vocabulary_id`. 3. Store the tag's `key` in the record field; use `label` and `color` only for display. Renaming a label does not change its stored key. System tags are protected from update and deletion. Deleting a user tag also removes that key from affected records; `entries_stripped` reports how many records changed. Removing one record's tag assignment instead uses that record's update operation. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | | `entries_stripped` | number | Yes | Number of source entries removed from the returned content. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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 | `tag_locked` | System tags cannot be deleted. | ## Next steps - [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) - [List tags](/developers/reference/customers/ListTags) - [Create tag](/developers/reference/customers/CreateTag) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.DeleteTag' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "vocabulary_id": "e_example", "key": "priority" }' ``` #### TypeScript ```typescript 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/customers.DeleteTag", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "vocabulary_id": "e_example", "key": "priority" }), }); 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 = { "vocabulary_id": "e_example", "key": "priority" } request = Request( "https://api.brigg.app/v1/operations/customers.DeleteTag", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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, "entries_stripped": 1 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "vocabulary_id": { "type": "string", "minLength": 1, "maxLength": 200, "description": "Select the vocabulary for the record's resource_type and field. Use vocabulary_id, not its display label. [customers.ListTagVocabularies](/developers/reference/customers/ListTagVocabularies)." }, "key": { "type": "string", "minLength": 1, "maxLength": 80, "description": "The tag's stable key." } }, "required": [ "vocabulary_id", "key" ], "additionalProperties": false, "examples": [ { "vocabulary_id": "e_example", "key": "priority" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." }, "entries_stripped": { "type": "number", "description": "Number of source entries removed from the returned content." } }, "required": [ "ok", "entries_stripped" ], "additionalProperties": false, "examples": [ { "ok": true, "entries_stripped": 1 } ] } ``` --- # Update tag Change a tag's label or colour while preserving its stable key. System tags cannot be changed. POST https://api.brigg.app/v1/operations/customers.UpdateTag ## Access & visibility Allow `customers.UpdateTag` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `vocabulary_id` | string | Yes | Select the vocabulary for the record's resource_type and field. Use vocabulary_id, not its display label. [customers.ListTagVocabularies](/developers/reference/customers/ListTagVocabularies). At least 1 character. At most 200 characters. | | `key` | string | Yes | The tag's stable key. At least 1 character. At most 80 characters. | | `label` | string | No | A new label. The key never changes. At least 1 character. At most 80 characters. | | `color` | string or null | No | A colour token, or null for none. | ## Use stored keys, not labels 1. [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) and select the record's `resource_type` and `field`. 2. [List tags](/developers/reference/customers/ListTags) with its `vocabulary_id`. 3. Store the tag's `key` in the record field; use `label` and `color` only for display. Renaming a label does not change its stored key. System tags are protected from update and deletion. Deleting a user tag also removes that key from affected records; `entries_stripped` reports how many records changed. Removing one record's tag assignment instead uses that record's update operation. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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 | `tag_locked` | System tags cannot be changed. | ## Next steps - [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) - [List tags](/developers/reference/customers/ListTags) - [Create tag](/developers/reference/customers/CreateTag) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/customers.UpdateTag' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "vocabulary_id": "e_example", "key": "priority" }' ``` #### TypeScript ```typescript 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/customers.UpdateTag", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "vocabulary_id": "e_example", "key": "priority" }), }); 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 = { "vocabulary_id": "e_example", "key": "priority" } request = Request( "https://api.brigg.app/v1/operations/customers.UpdateTag", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "vocabulary_id": { "type": "string", "minLength": 1, "maxLength": 200, "description": "Select the vocabulary for the record's resource_type and field. Use vocabulary_id, not its display label. [customers.ListTagVocabularies](/developers/reference/customers/ListTagVocabularies)." }, "key": { "type": "string", "minLength": 1, "maxLength": 80, "description": "The tag's stable key." }, "label": { "type": "string", "minLength": 1, "maxLength": 80, "description": "A new label. The key never changes." }, "color": { "anyOf": [ { "type": "string", "maxLength": 32 }, { "type": "null" } ], "description": "A colour token, or null for none." } }, "required": [ "vocabulary_id", "key" ], "additionalProperties": false, "examples": [ { "vocabulary_id": "e_example", "key": "priority" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." } }, "required": [ "ok" ], "additionalProperties": false, "examples": [ { "ok": true } ] } ``` --- # Copy bundle Copy readable content under a new name and return its content_id. The original stays unchanged. A shared document template becomes your personal template. The resulting location is returned when the copy is filed in Documents. POST https://api.brigg.app/v1/operations/documents.CopyBundle ## Access & visibility Allow `documents.CopyBundle` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `content_id` | string | Yes | Use content_id and check kind before choosing the operation. An app, template, website and uploaded file are not interchangeable. [workspace.ListBundles](/developers/reference/workspace/ListBundles). At least 1 character. | | `name` | string | Yes | The copy's display name. At least 1 character. At most 200 characters. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `content_id` | string | Yes | Opaque ID from workspace.ListBundles. Its kind distinguishes apps, websites, newsletters, documents, templates and integrations; it is not an uploaded file ID. | | `label` | string | Yes | Human-readable name for this content or saved version. | | `filed` | null or [object](#copybundlefiled-response-filed) | Yes | Where the copy was filed in Documents (`scope`, `path`); null when it is not a document. | ### CopyBundleFiled · response.filed | Field | Type | Required | Description | | --- | --- | --- | --- | | `scope` | string | Yes | Document collection: workspace or the acting member's personal collection, as allowed by this operation. Allowed: `"user"`, `"org"`. | | `path` | string | Yes | Folder path within the selected document collection. An empty string is its root. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | ## Next steps - [Upload and download files](/developers/files) - [List bundles](/developers/reference/workspace/ListBundles) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.CopyBundle' \ -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 '{ "content_id": "e_example", "name": "Consulting proposal" }' ``` #### 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/documents.CopyBundle", { 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({ "content_id": "e_example", "name": "Consulting proposal" }), }); 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 = { "content_id": "e_example", "name": "Consulting proposal" } request = Request( "https://api.brigg.app/v1/operations/documents.CopyBundle", 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 { "content_id": "e_example", "label": "Consulting proposal", "filed": null } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "content_id": { "type": "string", "minLength": 1, "description": "Use content_id and check kind before choosing the operation. An app, template, website and uploaded file are not interchangeable. [workspace.ListBundles](/developers/reference/workspace/ListBundles)." }, "name": { "type": "string", "minLength": 1, "maxLength": 200, "description": "The copy's display name." } }, "required": [ "content_id", "name" ], "additionalProperties": false, "examples": [ { "content_id": "e_example", "name": "Consulting proposal" } ] } ``` ```json-schema-response { "type": "object", "properties": { "content_id": { "type": "string", "description": "Opaque ID from workspace.ListBundles. Its kind distinguishes apps, websites, newsletters, documents, templates and integrations; it is not an uploaded file ID." }, "label": { "type": "string", "description": "Human-readable name for this content or saved version." }, "filed": { "description": "Where the copy was filed in Documents (`scope`, `path`); null when it is not a document.", "title": "CopyBundleFiled", "anyOf": [ { "type": "null" }, { "type": "object", "properties": { "scope": { "type": "string", "enum": [ "user", "org" ], "description": "Document collection: workspace or the acting member's personal collection, as allowed by this operation." }, "path": { "type": "string", "description": "Folder path within the selected document collection. An empty string is its root." } }, "required": [ "scope", "path" ], "additionalProperties": false } ] } }, "required": [ "content_id", "label", "filed" ], "additionalProperties": false, "examples": [ { "content_id": "e_example", "label": "Consulting proposal", "filed": null } ] } ``` --- # Create app Create an app, website or newsletter from a name, description, installed template, or built-in example. Returns a content ID and its Brigg URL. Content type, reusable and private options apply only when creating blank content; a clone keeps its source classification. POST https://api.brigg.app/v1/operations/documents.CreateApp ## Access & visibility Allow `documents.CreateApp` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `name` | string | No | The new bundle's display name. With a clone it overrides the source's label. At least 1 character. At most 200 characters. | | `description` | string | No | What to build — mints a blank bundle for a builder to fill in. At least 1 character. At most 2000 characters. | | `icon` | string | No | A sidebar icon from the curated catalog, on a blank mint. Allowed: `"default"`, `"home"`, `"users"`, `"shield"`, `"trophy"`, `"headphones"`, `"briefcase"`, `"award"`, `"building"`, `"scale"`, `"rocket"`, `"calendar"`, `"checklist"`, `"folder"`, `"graph"`, `"lightbulb"`, `"money"`, `"package"`, `"phone"`, `"puzzle"`, `"star"`, `"tag"`, `"cloud"`, `"globe"`, `"clock"`, `"receipt"`, `"book"`, `"chat"`, `"funnel"`, `"kanban"`, `"ticket"`. | | `content_type` | string | No | Media type of the file, such as application/pdf. Null when no binary file exists. Allowed: `"app"`, `"website"`, `"newsletter"`. | | `example_id` | string | No | Clone this built-in example (a `list_examples` slug). At least 1 character. At most 80 characters. | | `template_catalog_id` | string | No | Instantiate this installed template — its authoring slug (`list_templates` → `installed[].parent_template_slug`). At least 1 character. At most 80 characters. | | `reusable` | boolean | No | Blank mint only: a reusable template (hidden from the menu) rather than a one-off. | | `private` | boolean | No | Blank mint only: private to the caller (a signing document belongs to one person until signed). | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `content_id` | string | Yes | Opaque ID from workspace.ListBundles. Its kind distinguishes apps, websites, newsletters, documents, templates and integrations; it is not an uploaded file ID. | | `label` | string | Yes | Human-readable name for this content or saved version. | | `url` | string | Yes | Absolute URL, including its scheme. | | `version_id` | string or null | Yes | The version a clone's bytes were written to; null on a blank mint. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | ## Next steps - [Upload and download files](/developers/files) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.CreateApp' \ -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 '{}' ``` #### 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/documents.CreateApp", { 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({}), }); 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 = {} request = Request( "https://api.brigg.app/v1/operations/documents.CreateApp", 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 { "content_id": "e_example", "label": "Consulting proposal", "url": "https://example.com", "version_id": null } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 200, "description": "The new bundle's display name. With a clone it overrides the source's label." }, "description": { "type": "string", "minLength": 1, "maxLength": 2000, "description": "What to build — mints a blank bundle for a builder to fill in." }, "icon": { "type": "string", "enum": [ "default", "home", "users", "shield", "trophy", "headphones", "briefcase", "award", "building", "scale", "rocket", "calendar", "checklist", "folder", "graph", "lightbulb", "money", "package", "phone", "puzzle", "star", "tag", "cloud", "globe", "clock", "receipt", "book", "chat", "funnel", "kanban", "ticket" ], "description": "A sidebar icon from the curated catalog, on a blank mint." }, "content_type": { "type": "string", "enum": [ "app", "website", "newsletter" ], "description": "Media type of the file, such as application/pdf. Null when no binary file exists." }, "example_id": { "type": "string", "minLength": 1, "maxLength": 80, "description": "Clone this built-in example (a `list_examples` slug)." }, "template_catalog_id": { "type": "string", "minLength": 1, "maxLength": 80, "description": "Instantiate this installed template — its authoring slug (`list_templates` → `installed[].parent_template_slug`)." }, "reusable": { "type": "boolean", "description": "Blank mint only: a reusable template (hidden from the menu) rather than a one-off." }, "private": { "type": "boolean", "description": "Blank mint only: private to the caller (a signing document belongs to one person until signed)." } }, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "content_id": { "type": "string", "description": "Opaque ID from workspace.ListBundles. Its kind distinguishes apps, websites, newsletters, documents, templates and integrations; it is not an uploaded file ID." }, "label": { "type": "string", "description": "Human-readable name for this content or saved version." }, "url": { "type": "string", "description": "Absolute URL, including its scheme." }, "version_id": { "type": [ "string", "null" ], "description": "The version a clone's bytes were written to; null on a blank mint." } }, "required": [ "content_id", "label", "url", "version_id" ], "additionalProperties": false, "examples": [ { "content_id": "e_example", "label": "Consulting proposal", "url": "https://example.com", "version_id": null } ] } ``` --- # Delete content Permanently delete content identified by content_id. Requires authority to administer it; an active signing request prevents deletion. Reports retained fields whose values belong to records outside the deleted app. POST https://api.brigg.app/v1/operations/documents.DeleteBundle ## Access & visibility Allow `documents.DeleteBundle` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `content_id` | string | Yes | Use content_id and check kind before choosing the operation. An app, template, website and uploaded file are not interchangeable. [workspace.ListBundles](/developers/reference/workspace/ListBundles). At least 1 character. | ## Check the content before permanent deletion Select content_id and inspect kind in [List content](/developers/reference/workspace/ListBundles). This deletes the selected app, template, website or generated content and its associated artifacts. It is not the operation for deleting one customer record or an uploaded file; use the appropriate record operation or [Delete document](/developers/reference/documents/DeleteDocument). There is no public undo. The acting member needs workspace access and must own the content, have created it, or be a workspace owner or administrator. Workspace-managed material such as shared newsletters also permits workspace members; an ordinary shared app is not automatically administrable by every reader. A signing lock protects both a pending document and a completed signed record. Inspect signing state before attempting deletion. For apps, fields added to another resource type can survive when records outside this app still use them. retained_fields reports those definitions; an empty array means none needed retaining. A fresh deletion of an absent content_id returns app_not_found; retrying the original action with the same idempotency key can replay the original result. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | | `retained_fields` | array of [DeleteBundleRetainedExtensionFields](#deletebundleretainedextensionfields-response-retained-fields) | Yes | Field definitions retained because values still belong to records outside the deleted content. | ### DeleteBundleRetainedExtensionFields · response.retained_fields[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `target_type` | string | Yes | Resource type owned by another app whose records still contain values in fields added by the deleted app. | | `fields` | array of string | Yes | Names of extension fields retained on that resource type to preserve surviving record values. These are field keys, not template instructions or attachments. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | | 409 | `signing_locked` | A signing request protects this document from this change. Inspect its signing state in Brigg; completed signed records must not be destroyed. | | 404 | `app_not_found` | This content does not exist or is not visible. A fresh delete after successful removal also returns this code. | ## Next steps - [List bundles](/developers/reference/workspace/ListBundles) - [Delete document](/developers/reference/documents/DeleteDocument) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Delete selected content This fictional app added a field to Company records. Their existing values survive the app deletion. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.DeleteBundle' \ -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 '{ "content_id": "c_vendor_portal" }' ``` #### 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/documents.DeleteBundle", { 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({ "content_id": "c_vendor_portal" }), }); 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 = { "content_id": "c_vendor_portal" } request = Request( "https://api.brigg.app/v1/operations/documents.DeleteBundle", 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, "retained_fields": [ { "target_type": "core:Company", "fields": [ "vendor_portal_code" ] } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "content_id": { "type": "string", "minLength": 1, "description": "Use content_id and check kind before choosing the operation. An app, template, website and uploaded file are not interchangeable. [workspace.ListBundles](/developers/reference/workspace/ListBundles)." } }, "required": [ "content_id" ], "additionalProperties": false, "examples": [ { "content_id": "c_vendor_portal" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." }, "retained_fields": { "type": "array", "items": { "title": "DeleteBundleRetainedExtensionFields", "type": "object", "properties": { "target_type": { "type": "string", "description": "Resource type owned by another app whose records still contain values in fields added by the deleted app." }, "fields": { "type": "array", "items": { "type": "string" }, "description": "Names of extension fields retained on that resource type to preserve surviving record values. These are field keys, not template instructions or attachments." } }, "required": [ "target_type", "fields" ], "additionalProperties": false }, "description": "Field definitions retained because values still belong to records outside the deleted content." } }, "required": [ "ok", "retained_fields" ], "additionalProperties": false, "examples": [ { "ok": true, "retained_fields": [ { "target_type": "core:Company", "fields": [ "vendor_portal_code" ] } ] } ] } ``` --- # Rename content Rename an app, website, newsletter, document or template identified by content_id. Requires authority to administer that item. Does not change its ID or existing links. POST https://api.brigg.app/v1/operations/documents.RenameBundle ## Access & visibility Allow `documents.RenameBundle` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `content_id` | string | Yes | Use content_id and check kind before choosing the operation. An app, template, website and uploaded file are not interchangeable. [workspace.ListBundles](/developers/reference/workspace/ListBundles). At least 1 character. | | `name` | string | No | New content display name. Omit to keep the name when changing only icon_slug. At least 1 character. At most 80 characters. | | `icon_slug` | string or null | No | A sidebar icon from the curated catalog; null resets it to the derived default. | ## Response Returns **200 OK** with a JSON body. This changes the name or icon of content selected from ListBundles. It preserves content_id and does not copy, move or republish the content. The acting member must be allowed to administer it. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | ## Next steps - [List bundles](/developers/reference/workspace/ListBundles) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Rename existing content Pass at least the name or icon you intend to change. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.RenameBundle' \ -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 '{ "content_id": "c_vendor_portal", "name": "Supplier portal" }' ``` #### 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/documents.RenameBundle", { 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({ "content_id": "c_vendor_portal", "name": "Supplier portal" }), }); 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 = { "content_id": "c_vendor_portal", "name": "Supplier portal" } request = Request( "https://api.brigg.app/v1/operations/documents.RenameBundle", 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 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "content_id": { "type": "string", "minLength": 1, "description": "Use content_id and check kind before choosing the operation. An app, template, website and uploaded file are not interchangeable. [workspace.ListBundles](/developers/reference/workspace/ListBundles)." }, "name": { "type": "string", "minLength": 1, "maxLength": 80, "description": "New content display name. Omit to keep the name when changing only icon_slug." }, "icon_slug": { "anyOf": [ { "type": "string", "enum": [ "default", "home", "users", "shield", "trophy", "headphones", "briefcase", "award", "building", "scale", "rocket", "calendar", "checklist", "folder", "graph", "lightbulb", "money", "package", "phone", "puzzle", "star", "tag", "cloud", "globe", "clock", "receipt", "book", "chat", "funnel", "kanban", "ticket" ] }, { "type": "null" } ], "description": "A sidebar icon from the curated catalog; null resets it to the derived default." } }, "required": [ "content_id" ], "additionalProperties": false, "examples": [ { "content_id": "c_vendor_portal", "name": "Supplier portal" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." } }, "required": [ "ok" ], "additionalProperties": false, "examples": [ { "ok": true } ] } ``` --- # Attach document Attach an existing document to a record. Requires write access to that record's type. A document already attached elsewhere must be detached first. POST https://api.brigg.app/v1/operations/documents.AttachDocument ## Access & visibility Allow `documents.AttachDocument` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `file_id` | string | Yes | Use a file_id returned by this listing or by CompleteUpload. It is not an upload ID, storage path or filename. [documents.ListDocuments](/developers/reference/documents/ListDocuments). At least 1 character. | | `entry_id` | string | Yes | Record ID returned by the relevant record create, get or list operation. The credential needs access to that record's resource type. At least 1 character. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [Upload and download files](/developers/files) - [List documents](/developers/reference/documents/ListDocuments) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.AttachDocument' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "file_id": "e_example", "entry_id": "e_example" }' ``` #### TypeScript ```typescript 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/documents.AttachDocument", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "file_id": "e_example", "entry_id": "e_example" }), }); 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 = { "file_id": "e_example", "entry_id": "e_example" } request = Request( "https://api.brigg.app/v1/operations/documents.AttachDocument", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "file_id": { "type": "string", "minLength": 1, "description": "Use a file_id returned by this listing or by CompleteUpload. It is not an upload ID, storage path or filename. [documents.ListDocuments](/developers/reference/documents/ListDocuments)." }, "entry_id": { "type": "string", "minLength": 1, "description": "Record ID returned by the relevant record create, get or list operation. The credential needs access to that record's resource type." } }, "required": [ "file_id", "entry_id" ], "additionalProperties": false, "examples": [ { "file_id": "e_example", "entry_id": "e_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." } }, "required": [ "ok" ], "additionalProperties": false, "examples": [ { "ok": true } ] } ``` --- # Get Word fill job Check a Word-template job. A completed job includes the generated document and warnings; a failed job includes its reason. POST https://api.brigg.app/v1/operations/documents.GetWordFillJob ## Access & visibility Allow `documents.GetWordFillJob` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `job_id` | string | Yes | Exact job_id returned by FillWordTemplate. Use the same approved member; another member's job is not visible. At least 1 character. | ## Start, poll, then download Choose a Word template from [List templates](/developers/reference/workspace/ListTemplates): it must retain its original .docx. Supply a visible meeting_id, non-blank context, or both to [Fill Word template](/developers/reference/documents/FillWordTemplate). Starting a job uses workspace credit; the start response is not the generated document. Keep job_id and use [Get Word fill job](/developers/reference/documents/GetWordFillJob) under the same approved member. While status is pending, wait before polling again and honor Retry-After on rate limits. On done, review warnings and pass result.file_id to [Get file download](/developers/reference/documents/GetFileDownload). The resulting .docx belongs to that member. On failed, stop polling and review error; the result is not available. A cancelled job also reports failed. Repeating a start for the same member and template while matching work is in progress can return its job_id with deduped=true. Reuse the original idempotency key to recover a lost start response. After failure, a deliberate new attempt uses a new key and may consume more credit. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `status` | string | Yes | pending means work is still queued or running; done supplies result; failed supplies error and is terminal. A cancelled job is reported as failed. | | `result` | [object](#response-result) | No | Present only after successful completion. Use its file_id for download and inspect warnings before relying on the document. | | `error` | string | No | Terminal failure reason. Stop polling, inspect the cause and decide whether to start a new attempt. It is not an HTTP transport error. | ### response.result | Field | Type | Required | Description | | --- | --- | --- | --- | | `file_id` | string | Yes | Generated .docx file belonging to the member who started the fill. Pass it to GetFileDownload with the same member delegation. | | `filename` | string | Yes | Original filename, including its extension. | | `warnings` | array of string | Yes | Issues reported while generating the document; review the output before using it. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 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 Word job is missing, of another kind, or belongs to another member. Use its original job_id and approved member. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | | 409 | `result_unavailable` | The completed job's file is no longer accessible. Review it in Brigg rather than interpreting this as pending. | ## Next steps - [List templates](/developers/reference/workspace/ListTemplates) - [Fill Word template](/developers/reference/documents/FillWordTemplate) - [Get file download](/developers/reference/documents/GetFileDownload) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Generation is still running HTTP 200 confirms the status read, not completion. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.GetWordFillJob' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Brigg-Act-As: $BRIGG_ACT_AS" \ --data-raw '{ "job_id": "job_proposal" }' ``` #### 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 response = await fetch("https://api.brigg.app/v1/operations/documents.GetWordFillJob", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Brigg-Act-As": actAs, }, body: JSON.stringify({ "job_id": "job_proposal" }), }); 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 payload = { "job_id": "job_proposal" } request = Request( "https://api.brigg.app/v1/operations/documents.GetWordFillJob", 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"], }, 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 { "status": "pending" } ``` ### Download the generated document Inspect warnings, then use the returned file ID for download. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.GetWordFillJob' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Brigg-Act-As: $BRIGG_ACT_AS" \ --data-raw '{ "job_id": "job_proposal" }' ``` #### 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 response = await fetch("https://api.brigg.app/v1/operations/documents.GetWordFillJob", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Brigg-Act-As": actAs, }, body: JSON.stringify({ "job_id": "job_proposal" }), }); 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 payload = { "job_id": "job_proposal" } request = Request( "https://api.brigg.app/v1/operations/documents.GetWordFillJob", 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"], }, 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 { "status": "done", "result": { "file_id": "f_proposal", "filename": "Proposal.docx", "warnings": [] } } ``` ### Generation stopped Stop polling this job. A deliberate new attempt is a separate action. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.GetWordFillJob' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Brigg-Act-As: $BRIGG_ACT_AS" \ --data-raw '{ "job_id": "job_proposal" }' ``` #### 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 response = await fetch("https://api.brigg.app/v1/operations/documents.GetWordFillJob", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Brigg-Act-As": actAs, }, body: JSON.stringify({ "job_id": "job_proposal" }), }); 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 payload = { "job_id": "job_proposal" } request = Request( "https://api.brigg.app/v1/operations/documents.GetWordFillJob", 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"], }, 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 { "status": "failed", "error": "wordfill_failed" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "job_id": { "type": "string", "minLength": 1, "description": "Exact job_id returned by FillWordTemplate. Use the same approved member; another member's job is not visible." } }, "required": [ "job_id" ], "additionalProperties": false, "examples": [ { "job_id": "job_proposal" } ] } ``` ```json-schema-response { "type": "object", "properties": { "status": { "type": "string", "description": "pending means work is still queued or running; done supplies result; failed supplies error and is terminal. A cancelled job is reported as failed." }, "result": { "type": "object", "properties": { "file_id": { "type": "string", "description": "Generated .docx file belonging to the member who started the fill. Pass it to GetFileDownload with the same member delegation." }, "filename": { "type": "string", "description": "Original filename, including its extension." }, "warnings": { "type": "array", "items": { "type": "string" }, "description": "Issues reported while generating the document; review the output before using it." } }, "required": [ "file_id", "filename", "warnings" ], "additionalProperties": false, "description": "Present only after successful completion. Use its file_id for download and inspect warnings before relying on the document." }, "error": { "type": "string", "description": "Terminal failure reason. Stop polling, inspect the cause and decide whether to start a new attempt. It is not an HTTP transport error." } }, "required": [ "status" ], "additionalProperties": false, "examples": [ { "status": "pending" } ] } ``` --- # List document template fields List a template’s fields, inserted text documents and stable placement landmarks. Field IDs are used for updates and removal; landmark IDs choose where a new field goes. Editing a shared template requires its author or a workspace administrator. POST https://api.brigg.app/v1/operations/documents.ListDocumentTemplateFields ## Access & visibility Allow `documents.ListDocumentTemplateFields` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `template_id` | string | Yes | Use a template_id from the template catalogue; this is not the ID of a generated document. [workspace.ListTemplates](/developers/reference/workspace/ListTemplates). At least 1 character. | ## Inspect a template before editing it Find the `template_id` with [List templates](/developers/reference/workspace/ListTemplates). This is an editor's inspection operation: it requires the same template-management authority as the editing operations, even though it changes nothing. `items` contains generated fields and their instructions. `inserts` contains referenced text documents; `available: false` means the reference cannot currently be resolved for this caller, and `title` is null. `landmarks` is the ordered list of placement points for new fields or inserts. Use the returned IDs, never an offset into HTML. A template edit creates a new version. `version_id` identifies the version you inspected, not an optimistic-lock token accepted by the edit operations. Re-list after an edit before choosing another landmark. For placement at the end, no landmark is needed. ## Response Returns **200 OK** with a JSON body. This operation has no continuation cursor. An empty `items` array means no matching visible results were returned. | Field | Type | Required | Description | | --- | --- | --- | --- | | `version_id` | string | Yes | Version of the template inspected by this call. Editing creates a new version; this is not a field ID or an edit precondition. | | `inserts` | array of [Template insert](#template-insert-response-inserts) | Yes | Text documents inserted into this template at their selected versions. | | `landmarks` | array of [Template landmark](#template-landmark-response-landmarks) | Yes | Stable placement points that can be used when adding a field or insert. | | `items` | array of [Template field](#template-field-response-items) | Yes | Editable fields in the selected template version; inserts and placement landmarks are returned separately. This operation has no cursor pagination. | ### Template insert · response.inserts[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `field_id` | string | Yes | Stable field or insert ID returned by documents.ListDocumentTemplateFields. It stays the same when its instruction or layout is edited. | | `file_id` | string | Yes | Stable file ID returned by documents.CompleteUpload, documents.ListDocuments or a document creation operation. Use the same ID for downloads, attachments and supported file-based workflows. Do not use a filename or storage path. | | `layout` | string | No | Display layout for the inserted text document. Allowed: `"one-column"`, `"two-column"`, `"compact"`. | | `title` | null or string | Yes | Referenced text document's filename, or null when unavailable to this caller. | | `available` | boolean | Yes | Whether this referenced content is currently available to the caller. Allowed: `false`, `true`. | ### Template landmark · response.landmarks[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `landmark_id` | string | Yes | Stable insertion landmark from documents.ListDocumentTemplateFields. Use it with position before or after; position end needs no landmark. | | `kind` | string | Yes | Placement-point kind: blocks for fixed content, field for a generated field, or insert for an inserted text document. | ### Template field · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `field_id` | string | Yes | Stable field or insert ID returned by documents.ListDocumentTemplateFields. It stays the same when its instruction or layout is edited. | | `instruction` | string | Yes | Instructions used to fill this field when generating a document from the template. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 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. | | 409 | `signing_locked` | Pending or completed signing protects this template. Do not retry the edit unchanged. | | 400 | `not_a_template` | Choose a document template from ListTemplates, not a generated document. | | 404 | `no_active_version` | This template has no editable version. Open it in Brigg to complete its setup. | ## Next steps - [List templates](/developers/reference/workspace/ListTemplates) - [Add document template field](/developers/reference/documents/AddDocumentTemplateField) - [Update document template field](/developers/reference/documents/UpdateDocumentTemplateField) - [Remove document template field](/developers/reference/documents/RemoveDocumentTemplateField) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Fields, inserts and placement points All three collections are independent. Save the exact field and landmark IDs returned by your template. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.ListDocumentTemplateFields' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Brigg-Act-As: $BRIGG_ACT_AS" \ --data-raw '{ "template_id": "c_template_proposal" }' ``` #### 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 response = await fetch("https://api.brigg.app/v1/operations/documents.ListDocumentTemplateFields", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Brigg-Act-As": actAs, }, body: JSON.stringify({ "template_id": "c_template_proposal" }), }); 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 payload = { "template_id": "c_template_proposal" } request = Request( "https://api.brigg.app/v1/operations/documents.ListDocumentTemplateFields", 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"], }, 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 { "version_id": "v_proposal_3", "items": [ { "field_id": "project-summary", "instruction": "Summarize the project objectives and agreed deliverables." } ], "inserts": [ { "field_id": "terms", "file_id": "f_terms", "layout": "one-column", "title": "Standard terms", "available": true } ], "landmarks": [ { "landmark_id": "introduction", "kind": "blocks" }, { "landmark_id": "project-summary", "kind": "field" }, { "landmark_id": "terms", "kind": "insert" } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "template_id": { "type": "string", "minLength": 1, "description": "Use a template_id from the template catalogue; this is not the ID of a generated document. [workspace.ListTemplates](/developers/reference/workspace/ListTemplates)." } }, "required": [ "template_id" ], "additionalProperties": false, "examples": [ { "template_id": "c_template_proposal" } ] } ``` ```json-schema-response { "type": "object", "properties": { "version_id": { "type": "string", "description": "Version of the template inspected by this call. Editing creates a new version; this is not a field ID or an edit precondition." }, "inserts": { "type": "array", "items": { "title": "Template insert", "type": "object", "properties": { "field_id": { "type": "string", "description": "Stable field or insert ID returned by documents.ListDocumentTemplateFields. It stays the same when its instruction or layout is edited." }, "file_id": { "type": "string", "description": "Stable file ID returned by documents.CompleteUpload, documents.ListDocuments or a document creation operation. Use the same ID for downloads, attachments and supported file-based workflows. Do not use a filename or storage path." }, "layout": { "type": "string", "enum": [ "one-column", "two-column", "compact" ], "description": "Display layout for the inserted text document." }, "title": { "anyOf": [ { "type": "null", "description": "Referenced text document's filename, or null when unavailable to this caller." }, { "type": "string", "description": "Referenced text document's filename, or null when unavailable to this caller." } ], "description": "Referenced text document's filename, or null when unavailable to this caller." }, "available": { "type": "boolean", "enum": [ false, true ], "description": "Whether this referenced content is currently available to the caller." } }, "required": [ "field_id", "file_id", "title", "available" ], "additionalProperties": false }, "description": "Text documents inserted into this template at their selected versions." }, "landmarks": { "type": "array", "items": { "type": "object", "properties": { "landmark_id": { "type": "string", "description": "Stable insertion landmark from documents.ListDocumentTemplateFields. Use it with position before or after; position end needs no landmark." }, "kind": { "type": "string", "description": "Placement-point kind: blocks for fixed content, field for a generated field, or insert for an inserted text document." } }, "required": [ "landmark_id", "kind" ], "additionalProperties": false, "title": "Template landmark" }, "description": "Stable placement points that can be used when adding a field or insert." }, "items": { "type": "array", "items": { "title": "Template field", "type": "object", "properties": { "field_id": { "type": "string", "description": "Stable field or insert ID returned by documents.ListDocumentTemplateFields. It stays the same when its instruction or layout is edited.", "examples": [ "project_summary" ] }, "instruction": { "type": "string", "description": "Instructions used to fill this field when generating a document from the template.", "examples": [ "Summarize the project objectives and agreed deliverables." ] } }, "required": [ "field_id", "instruction" ], "additionalProperties": false }, "description": "Editable fields in the selected template version; inserts and placement landmarks are returned separately. This operation has no cursor pagination." } }, "required": [ "version_id", "items", "inserts", "landmarks" ], "additionalProperties": false, "examples": [ { "version_id": "v_proposal_3", "items": [ { "field_id": "project-summary", "instruction": "Summarize the project objectives and agreed deliverables." } ], "inserts": [ { "field_id": "terms", "file_id": "f_terms", "layout": "one-column", "title": "Standard terms", "available": true } ], "landmarks": [ { "landmark_id": "introduction", "kind": "blocks" }, { "landmark_id": "project-summary", "kind": "field" }, { "landmark_id": "terms", "kind": "insert" } ] } ] } ``` --- # Add document template field Add a named field or a text-document insert to a template. Choose before or after a landmark returned by ListDocumentTemplateFields, or end. A field is filled from its instruction; an insert copies its selected text document at a pinned version when a document is generated. Returns the stable field ID and draft version. POST https://api.brigg.app/v1/operations/documents.AddDocumentTemplateField ## Access & visibility Allow `documents.AddDocumentTemplateField` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/permissions) ## Request fields Send a JSON object with the following fields. Required fields must be included; omit optional fields you do not need. #### kind = "field" | Field | Type | Required | Description | | --- | --- | --- | --- | | `template_id` | string | Yes | Use a template_id from the template catalogue; this is not the ID of a generated document. [workspace.ListTemplates](/developers/reference/workspace/ListTemplates). At least 1 character. | | `kind` | string | Yes | field adds generated text from an instruction; insert references an existing collaborative text document. Choose one request variant. Always `"field"`. | | `instruction` | string | Yes | Instructions used to fill this template field. At least 1 character. At most 500 characters. | | `placement` | [object (2 variants)](#request-variant1-placement) | Yes | Place the field before or after a named landmark, or at the end of the template. List the current landmarks first. No HTML or byte offset is accepted. | ### request.variant1.placement #### Variant 1 | Field | Type | Required | Description | | --- | --- | --- | --- | | `position` | string | Yes | Where to place the new field or insert relative to a landmark, or at the end. Allowed: `"before"`, `"after"`. | | `landmark_id` | string | Yes | Stable insertion landmark from documents.ListDocumentTemplateFields. Use it with position before or after; position end needs no landmark. Pattern: `^[a-z0-9][a-z0-9-]{0,63}$`. | #### position = "end" | Field | Type | Required | Description | | --- | --- | --- | --- | | `position` | string | Yes | Where to place the new field or insert relative to a landmark, or at the end. Always `"end"`. | #### kind = "insert" | Field | Type | Required | Description | | --- | --- | --- | --- | | `template_id` | string | Yes | Use a template_id from the template catalogue; this is not the ID of a generated document. [workspace.ListTemplates](/developers/reference/workspace/ListTemplates). At least 1 character. | | `kind` | string | Yes | field adds generated text from an instruction; insert references an existing collaborative text document. Choose one request variant. Always `"insert"`. | | `file_id` | string | Yes | An existing collaborative text document from ListDocuments (kind=text_document). An uploaded PDF is not an insertable text document. At least 1 character. | | `layout` | string | No | Display layout for the inserted text document. Allowed: `"one-column"`, `"two-column"`, `"compact"`. | | `placement` | [object (2 variants)](#request-variant2-placement) | Yes | Place the field before or after a named landmark, or at the end of the template. List the current landmarks first. No HTML or byte offset is accepted. | ### request.variant2.placement #### Variant 1 | Field | Type | Required | Description | | --- | --- | --- | --- | | `position` | string | Yes | Where to place the new field or insert relative to a landmark, or at the end. Allowed: `"before"`, `"after"`. | | `landmark_id` | string | Yes | Stable insertion landmark from documents.ListDocumentTemplateFields. Use it with position before or after; position end needs no landmark. Pattern: `^[a-z0-9][a-z0-9-]{0,63}$`. | #### position = "end" | Field | Type | Required | Description | | --- | --- | --- | --- | | `position` | string | Yes | Where to place the new field or insert relative to a landmark, or at the end. Always `"end"`. | ## Inspect, edit, then inspect again Use [List document template fields](/developers/reference/documents/ListDocumentTemplateFields) to get this template's generated fields, inserted documents and placement landmarks. A generated field contains an instruction; an insert references an existing text document. Use the returned field_id names and landmark_id values exactly. Edits create a new template version and require template-management authority, not just read access. Pending or completed signing can lock the template. Existing generated documents are not regenerated by a template edit. The returned version_id records the changed template; it is not a precondition for another edit. Re-list before selecting a placement in the changed structure. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `field_id` | string | Yes | Server-assigned stable field or insert name. Keep it for subsequent instruction/layout changes or removal. | | `version_id` | string | Yes | New template version containing this edit. It is not a collaborative text-document version or an optimistic-lock token. Re-list template fields to inspect the current structure after the edit. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | | 409 | `signing_locked` | Pending or completed signing protects this template. Do not retry the edit unchanged. | | 400 | `not_a_template` | Choose a document template from ListTemplates, not a generated document. | | 404 | `no_active_version` | This template has no editable version. Open it in Brigg to complete its setup. | | 409 | `anchor_not_found` | The placement landmark no longer exists. Re-list template fields before selecting a position. | | 409 | `anchor_ambiguous` | The landmark does not uniquely identify a position. Inspect the template and choose another current landmark or position end. | | 400 | `not_a_text_document` | The insert must reference a collaborative text document; an uploaded PDF or generated document is not valid here. | ## Next steps - [List document template fields](/developers/reference/documents/ListDocumentTemplateFields) - [Update document template field](/developers/reference/documents/UpdateDocumentTemplateField) - [Remove document template field](/developers/reference/documents/RemoveDocumentTemplateField) - [List documents](/developers/reference/documents/ListDocuments) - [List templates](/developers/reference/workspace/ListTemplates) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Add generated text at the end Brigg assigns the field ID; the instruction supplies the generation behavior. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.AddDocumentTemplateField' \ -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 '{ "template_id": "c_template_proposal", "kind": "field", "instruction": "Summarize the project objectives and agreed deliverables.", "placement": { "position": "end" } }' ``` #### 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/documents.AddDocumentTemplateField", { 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({ "template_id": "c_template_proposal", "kind": "field", "instruction": "Summarize the project objectives and agreed deliverables.", "placement": { "position": "end" } }), }); 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 = { "template_id": "c_template_proposal", "kind": "field", "instruction": "Summarize the project objectives and agreed deliverables.", "placement": { "position": "end" } } request = Request( "https://api.brigg.app/v1/operations/documents.AddDocumentTemplateField", 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 { "field_id": "field-2", "version_id": "v_proposal_4" } ``` ### Insert existing terms after a landmark Use an exact current landmark and a readable collaborative text document. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.AddDocumentTemplateField' \ -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 '{ "template_id": "c_template_proposal", "kind": "insert", "file_id": "f_terms", "layout": "one-column", "placement": { "position": "after", "landmark_id": "project-summary" } }' ``` #### 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/documents.AddDocumentTemplateField", { 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({ "template_id": "c_template_proposal", "kind": "insert", "file_id": "f_terms", "layout": "one-column", "placement": { "position": "after", "landmark_id": "project-summary" } }), }); 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 = { "template_id": "c_template_proposal", "kind": "insert", "file_id": "f_terms", "layout": "one-column", "placement": { "position": "after", "landmark_id": "project-summary" } } request = Request( "https://api.brigg.app/v1/operations/documents.AddDocumentTemplateField", 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 { "field_id": "insert-2", "version_id": "v_proposal_4" } ``` ## JSON schemas ```json-schema-request { "anyOf": [ { "type": "object", "properties": { "template_id": { "type": "string", "minLength": 1, "description": "Use a template_id from the template catalogue; this is not the ID of a generated document. [workspace.ListTemplates](/developers/reference/workspace/ListTemplates)." }, "kind": { "type": "string", "const": "field", "description": "field adds generated text from an instruction; insert references an existing collaborative text document. Choose one request variant." }, "instruction": { "type": "string", "minLength": 1, "maxLength": 500, "description": "Instructions used to fill this template field." }, "placement": { "anyOf": [ { "type": "object", "properties": { "position": { "type": "string", "enum": [ "before", "after" ], "description": "Where to place the new field or insert relative to a landmark, or at the end." }, "landmark_id": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]{0,63}$", "description": "Stable insertion landmark from documents.ListDocumentTemplateFields. Use it with position before or after; position end needs no landmark." } }, "required": [ "position", "landmark_id" ], "additionalProperties": false }, { "type": "object", "properties": { "position": { "type": "string", "const": "end", "description": "Where to place the new field or insert relative to a landmark, or at the end." } }, "required": [ "position" ], "additionalProperties": false } ], "description": "Place the field before or after a named landmark, or at the end of the template. List the current landmarks first. No HTML or byte offset is accepted." } }, "required": [ "template_id", "kind", "instruction", "placement" ], "additionalProperties": false }, { "type": "object", "properties": { "template_id": { "type": "string", "minLength": 1, "description": "Use a template_id from the template catalogue; this is not the ID of a generated document. [workspace.ListTemplates](/developers/reference/workspace/ListTemplates)." }, "kind": { "type": "string", "const": "insert", "description": "field adds generated text from an instruction; insert references an existing collaborative text document. Choose one request variant." }, "file_id": { "type": "string", "minLength": 1, "description": "An existing collaborative text document from ListDocuments (kind=text_document). An uploaded PDF is not an insertable text document." }, "layout": { "type": "string", "enum": [ "one-column", "two-column", "compact" ], "description": "Display layout for the inserted text document." }, "placement": { "anyOf": [ { "type": "object", "properties": { "position": { "type": "string", "enum": [ "before", "after" ], "description": "Where to place the new field or insert relative to a landmark, or at the end." }, "landmark_id": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]{0,63}$", "description": "Stable insertion landmark from documents.ListDocumentTemplateFields. Use it with position before or after; position end needs no landmark." } }, "required": [ "position", "landmark_id" ], "additionalProperties": false }, { "type": "object", "properties": { "position": { "type": "string", "const": "end", "description": "Where to place the new field or insert relative to a landmark, or at the end." } }, "required": [ "position" ], "additionalProperties": false } ], "description": "Place the field before or after a named landmark, or at the end of the template. List the current landmarks first. No HTML or byte offset is accepted." } }, "required": [ "template_id", "kind", "file_id", "placement" ], "additionalProperties": false } ], "examples": [ { "template_id": "c_template_proposal", "kind": "field", "instruction": "Summarize the project objectives and agreed deliverables.", "placement": { "position": "end" } } ] } ``` ```json-schema-response { "type": "object", "properties": { "field_id": { "type": "string", "description": "Server-assigned stable field or insert name. Keep it for subsequent instruction/layout changes or removal." }, "version_id": { "type": "string", "description": "New template version containing this edit. It is not a collaborative text-document version or an optimistic-lock token. Re-list template fields to inspect the current structure after the edit." } }, "required": [ "field_id", "version_id" ], "additionalProperties": false, "examples": [ { "field_id": "field-2", "version_id": "v_proposal_4" } ] } ``` --- # Delete document template Permanently delete a document template. A template awaiting signatures cannot be deleted. POST https://api.brigg.app/v1/operations/documents.DeleteDocumentTemplate ## Access & visibility Allow `documents.DeleteDocumentTemplate` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `template_id` | string | Yes | Use a template_id from the template catalogue; this is not the ID of a generated document. [workspace.ListTemplates](/developers/reference/workspace/ListTemplates). At least 1 character. | ## Response Returns **200 OK** with a JSON body. The acting member must own the template, have created it, or be a workspace owner or administrator. Being able to read a shared template does not by itself allow changing or deleting it. Permanent deletion has no public undo. This targets the template, not each document previously generated from it. Confirm the template ID in ListTemplates before deleting. A signing lock can prevent deletion. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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` | The acting member must own the template, have created it, or currently be a workspace owner or administrator. Read access alone is insufficient. | | 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. | | 409 | `signing_locked` | A signing request protects this document from this change. Inspect its signing state in Brigg; completed signed records must not be destroyed. | | 404 | `template_not_found` | Choose a document template from ListTemplates; app and newsletter templates are not accepted. | ## Next steps - [List templates](/developers/reference/workspace/ListTemplates) - [Update document template](/developers/reference/documents/UpdateDocumentTemplate) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Delete the selected template The template is no longer available for creating new documents. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.DeleteDocumentTemplate' \ -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 '{ "template_id": "c_template_proposal" }' ``` #### 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/documents.DeleteDocumentTemplate", { 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({ "template_id": "c_template_proposal" }), }); 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 = { "template_id": "c_template_proposal" } request = Request( "https://api.brigg.app/v1/operations/documents.DeleteDocumentTemplate", 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 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "template_id": { "type": "string", "minLength": 1, "description": "Use a template_id from the template catalogue; this is not the ID of a generated document. [workspace.ListTemplates](/developers/reference/workspace/ListTemplates)." } }, "required": [ "template_id" ], "additionalProperties": false, "examples": [ { "template_id": "c_template_proposal" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." } }, "required": [ "ok" ], "additionalProperties": false, "examples": [ { "ok": true } ] } ``` --- # Fill Word template Generate a Word document from a template and meeting content or supplied text. Uses workspace credit. Read workspace.GetJob using the returned job_id to track progress and obtain file_id; repeated requests for the same material reuse the active job. POST https://api.brigg.app/v1/operations/documents.FillWordTemplate ## Access & visibility Allow `documents.FillWordTemplate` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `template_id` | string | Yes | Use a template_id from the template catalogue; this is not the ID of a generated document. [workspace.ListTemplates](/developers/reference/workspace/ListTemplates). At least 1 character. | | `meeting_id` | string | No | Visible Meeting record ID from [List meetings](/developers/reference/meetings/ListMeetings). Supply meeting_id, nonblank context, or both; at least one source is required. At least 1 character. | | `context` | string | No | Source material to use when filling the Word template. Supply nonblank text, a meeting_id, or both. Whitespace alone does not provide material. At least 1 character. | ## Prepare the source and retrieve the result Choose a template created from an original .docx in Brigg, then obtain its template_id from [List templates](/developers/reference/workspace/ListTemplates). The catalogue currently has no Word-capability flag: a normal HTML template cannot be filled by this operation. A not_a_word_template error means choose a Word-backed template; source_missing means repair that template in Brigg. Provide meeting_id, nonblank context, or both. Keep the returned job_id and poll [Get job](/developers/reference/workspace/GetJob) as the same member. A successful start is queued work, not a finished document. When completed, pass result.file_id to [Get file download](/developers/reference/documents/GetFileDownload) for the .docx. While work is active, the same member/template/meeting reuses that job; for context-only work the text identifies the active request. Changing extra context while a meeting-based job runs does not start a second job. Idempotency-Key independently protects retries of one HTTP action. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `job_id` | string | Yes | Job ID to pass to workspace.GetJob for progress and the resulting file_id. Poll with the same approved acting member. | | `deduped` | boolean | No | Whether this call reused work already in progress for the same material. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | | 400 | `no_material` | Supply a meeting_id, nonblank context, or both. | | 404 | `template_not_found` | Choose a template visible to the same acting member. | | 400 | `not_a_word_template` | Choose a template prepared from an original .docx in Brigg; ordinary HTML templates cannot be filled here. | | 400 | `source_missing` | Restore the template's original Word file in Brigg. | | 402 | `insufficient_credits` | Refill workspace credit before starting the job. | | 502 | `dispatch_failed` | The background job could not be started. Retry the logical request rather than assuming a document was produced. | ## Next steps - [List templates](/developers/reference/workspace/ListTemplates) - [List meetings](/developers/reference/meetings/ListMeetings) - [Get job](/developers/reference/workspace/GetJob) - [Get file download](/developers/reference/documents/GetFileDownload) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Fill from supplied material Use a Word-backed template from your workspace. The returned job is still running. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.FillWordTemplate' \ -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 '{ "template_id": "template_consulting", "context": "Prepare the agreement for Northstar Consulting AS. A two-week onboarding project starts on 16 November 2026, at a fixed fee of NOK 25,000 excluding VAT." }' ``` #### 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/documents.FillWordTemplate", { 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({ "template_id": "template_consulting", "context": "Prepare the agreement for Northstar Consulting AS. A two-week onboarding project starts on 16 November 2026, at a fixed fee of NOK 25,000 excluding VAT." }), }); 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 = { "template_id": "template_consulting", "context": "Prepare the agreement for Northstar Consulting AS. A two-week onboarding project starts on 16 November 2026, at a fixed fee of NOK 25,000 excluding VAT." } request = Request( "https://api.brigg.app/v1/operations/documents.FillWordTemplate", 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 { "job_id": "job_word_agreement" } ``` ### Fill from a meeting A repeated start can reuse the active job. Poll the returned ID rather than submitting another request. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.FillWordTemplate' \ -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 '{ "template_id": "template_consulting", "meeting_id": "e_meeting_kickoff", "context": "Use the agreed deliverables and owners from this meeting." }' ``` #### 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/documents.FillWordTemplate", { 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({ "template_id": "template_consulting", "meeting_id": "e_meeting_kickoff", "context": "Use the agreed deliverables and owners from this meeting." }), }); 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 = { "template_id": "template_consulting", "meeting_id": "e_meeting_kickoff", "context": "Use the agreed deliverables and owners from this meeting." } request = Request( "https://api.brigg.app/v1/operations/documents.FillWordTemplate", 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 { "job_id": "job_word_agreement", "deduped": true } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "template_id": { "type": "string", "minLength": 1, "description": "Use a template_id from the template catalogue; this is not the ID of a generated document. [workspace.ListTemplates](/developers/reference/workspace/ListTemplates)." }, "meeting_id": { "type": "string", "minLength": 1, "description": "Visible Meeting record ID from [List meetings](/developers/reference/meetings/ListMeetings). Supply meeting_id, nonblank context, or both; at least one source is required." }, "context": { "type": "string", "minLength": 1, "description": "Source material to use when filling the Word template. Supply nonblank text, a meeting_id, or both. Whitespace alone does not provide material." } }, "required": [ "template_id" ], "additionalProperties": false, "examples": [ { "template_id": "template_consulting", "context": "Prepare the agreement for Northstar Consulting AS. A two-week onboarding project starts on 16 November 2026, at a fixed fee of NOK 25,000 excluding VAT." } ] } ``` ```json-schema-response { "type": "object", "properties": { "job_id": { "type": "string", "description": "Job ID to pass to workspace.GetJob for progress and the resulting file_id. Poll with the same approved acting member." }, "deduped": { "type": "boolean", "description": "Whether this call reused work already in progress for the same material." } }, "required": [ "job_id" ], "additionalProperties": false, "examples": [ { "job_id": "job_word_agreement" } ] } ``` --- # Install document template Install a built-in document template using its catalog identifier. Repeating the request returns the existing template with installed: false. POST https://api.brigg.app/v1/operations/documents.InstallDocumentTemplate ## Access & visibility Allow `documents.InstallDocumentTemplate` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `catalog_id` | string | Yes | Authoring slug. At least 1 character. At most 120 characters. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `template_id` | string | Yes | Template ID from workspace.ListTemplates. This is distinct from a generated document's file_id. | | `label` | string | Yes | Human-readable name for this content or saved version. | | `installed` | boolean | Yes | True when the template was newly installed; false when an existing installation was returned. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | ## Next steps - [Upload and download files](/developers/files) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.InstallDocumentTemplate' \ -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 '{ "catalog_id": "e_example" }' ``` #### 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/documents.InstallDocumentTemplate", { 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({ "catalog_id": "e_example" }), }); 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 = { "catalog_id": "e_example" } request = Request( "https://api.brigg.app/v1/operations/documents.InstallDocumentTemplate", 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 { "template_id": "e_example", "label": "Consulting proposal", "installed": false } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "catalog_id": { "type": "string", "minLength": 1, "maxLength": 120, "description": "Authoring slug." } }, "required": [ "catalog_id" ], "additionalProperties": false, "examples": [ { "catalog_id": "e_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "template_id": { "type": "string", "description": "Template ID from workspace.ListTemplates. This is distinct from a generated document's file_id." }, "label": { "type": "string", "description": "Human-readable name for this content or saved version." }, "installed": { "type": "boolean", "description": "True when the template was newly installed; false when an existing installation was returned." } }, "required": [ "template_id", "label", "installed" ], "additionalProperties": false, "examples": [ { "template_id": "e_example", "label": "Consulting proposal", "installed": false } ] } ``` --- # Remove document template field Remove a template field or inserted document by field_id. Removes its definition and every occurrence together. Other wording remains unchanged. A template locked for signing cannot be edited. POST https://api.brigg.app/v1/operations/documents.RemoveDocumentTemplateField ## Access & visibility Allow `documents.RemoveDocumentTemplateField` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `template_id` | string | Yes | Use a template_id from the template catalogue; this is not the ID of a generated document. [workspace.ListTemplates](/developers/reference/workspace/ListTemplates). At least 1 character. | | `field_id` | string | Yes | Exact field_id from items or inserts in ListDocumentTemplateFields for this same template_id. It is a stable name, not an array index, display label or file ID. Pattern: `^[a-z0-9][a-z0-9-]{0,63}$`. | ## Inspect, edit, then inspect again Use [List document template fields](/developers/reference/documents/ListDocumentTemplateFields) to get this template's generated fields, inserted documents and placement landmarks. A generated field contains an instruction; an insert references an existing text document. Use the returned field_id names and landmark_id values exactly. Edits create a new template version and require template-management authority, not just read access. Pending or completed signing can lock the template. Existing generated documents are not regenerated by a template edit. The returned version_id records the changed template; it is not a precondition for another edit. Re-list before selecting a placement in the changed structure. ## Response Returns **200 OK** with a JSON body. Removes the definition and every placement of this field or insert from the template. Removing an insert leaves its underlying text document intact; deleting the field does not rewrite documents previously generated from this template. Re-list before another edit because landmarks can change. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | | `version_id` | string | Yes | New template version containing this edit. It is not a collaborative text-document version or an optimistic-lock token. Re-list template fields to inspect the current structure after the edit. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | | 409 | `signing_locked` | Pending or completed signing protects this template. Do not retry the edit unchanged. | | 400 | `not_a_template` | Choose a document template from ListTemplates, not a generated document. | | 404 | `no_active_version` | This template has no editable version. Open it in Brigg to complete its setup. | | 404 | `slot_not_found` | Re-list this template's fields and inserts; use an exact current field_id. | ## Next steps - [List document template fields](/developers/reference/documents/ListDocumentTemplateFields) - [Add document template field](/developers/reference/documents/AddDocumentTemplateField) - [Update document template field](/developers/reference/documents/UpdateDocumentTemplateField) - [List templates](/developers/reference/workspace/ListTemplates) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Remove the project summary field Inspect ListDocumentTemplateFields first and choose the exact field name. This edits the template, not one generated document. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.RemoveDocumentTemplateField' \ -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 '{ "template_id": "c_template_proposal", "field_id": "project-summary" }' ``` #### 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/documents.RemoveDocumentTemplateField", { 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({ "template_id": "c_template_proposal", "field_id": "project-summary" }), }); 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 = { "template_id": "c_template_proposal", "field_id": "project-summary" } request = Request( "https://api.brigg.app/v1/operations/documents.RemoveDocumentTemplateField", 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, "version_id": "v_proposal_4" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "template_id": { "type": "string", "minLength": 1, "description": "Use a template_id from the template catalogue; this is not the ID of a generated document. [workspace.ListTemplates](/developers/reference/workspace/ListTemplates)." }, "field_id": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]{0,63}$", "description": "Exact field_id from items or inserts in ListDocumentTemplateFields for this same template_id. It is a stable name, not an array index, display label or file ID." } }, "required": [ "template_id", "field_id" ], "additionalProperties": false, "examples": [ { "template_id": "c_template_proposal", "field_id": "project-summary" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." }, "version_id": { "type": "string", "description": "New template version containing this edit. It is not a collaborative text-document version or an optimistic-lock token. Re-list template fields to inspect the current structure after the edit." } }, "required": [ "ok", "version_id" ], "additionalProperties": false, "examples": [ { "ok": true, "version_id": "v_proposal_4" } ] } ``` --- # Update document template Rename a document template or change its workspace sharing. Editing requires the template’s owner, creator or a workspace administrator. POST https://api.brigg.app/v1/operations/documents.UpdateDocumentTemplate ## Access & visibility Allow `documents.UpdateDocumentTemplate` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `template_id` | string | Yes | Use a template_id from the template catalogue; this is not the ID of a generated document. [workspace.ListTemplates](/developers/reference/workspace/ListTemplates). At least 1 character. | | `label` | string | No | New display name for the template. Omit to preserve the name; this does not edit its document content or fields. At least 1 character. At most 200 characters. | | `level` | string | No | org shares with the workspace; user returns it to its original creator when that person is still a member, otherwise to the acting member. Omit to preserve sharing. Allowed: `"org"`, `"user"`. | ## Rename or share an existing document template Choose a document template from [List templates](/developers/reference/workspace/ListTemplates). App templates and newsletter templates are different resources and are not accepted here. A change to level affects future template discovery; it does not rewrite documents already generated from that template. Making a template private removes it from colleagues’ normal lists, but keeps any existing saved version. It does not retract bytes already downloaded or make earlier copies disappear. Read ListTemplates again to confirm the resulting label and owner_account_id. ## Response Returns **200 OK** with a JSON body. The acting member must own the template, have created it, or be a workspace owner or administrator. Being able to read a shared template does not by itself allow changing or deleting it. Send label, level, or both. Omitting both makes no requested metadata change. This operation does not change template instructions; use the template-field operations for those. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | The requested metadata changes were saved. | | `published` | boolean | Yes | True only when this sharing change created an initial saved content version so colleagues can render the template. False for a rename, making it private, or sharing a template that already had a saved version. This is not a current-publication or public-web visibility flag. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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` | The acting member must own the template, have created it, or currently be a workspace owner or administrator. Read access alone is insufficient. | | 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. | | 404 | `template_not_found` | Choose a document template from ListTemplates; app and newsletter templates are not accepted. | ## Next steps - [List templates](/developers/reference/workspace/ListTemplates) - [List document template fields](/developers/reference/documents/ListDocumentTemplateFields) - [Delete document template](/developers/reference/documents/DeleteDocumentTemplate) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Rename without changing access Omitted level preserves current sharing. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.UpdateDocumentTemplate' \ -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 '{ "template_id": "c_template_proposal", "label": "Project proposal" }' ``` #### 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/documents.UpdateDocumentTemplate", { 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({ "template_id": "c_template_proposal", "label": "Project proposal" }), }); 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 = { "template_id": "c_template_proposal", "label": "Project proposal" } request = Request( "https://api.brigg.app/v1/operations/documents.UpdateDocumentTemplate", 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, "published": false } ``` ### Share a personal template This example template has no saved version yet, so sharing creates one. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.UpdateDocumentTemplate' \ -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 '{ "template_id": "c_template_proposal", "level": "org" }' ``` #### 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/documents.UpdateDocumentTemplate", { 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({ "template_id": "c_template_proposal", "level": "org" }), }); 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 = { "template_id": "c_template_proposal", "level": "org" } request = Request( "https://api.brigg.app/v1/operations/documents.UpdateDocumentTemplate", 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, "published": true } ``` ### Return a template to personal use The creator still belongs to the workspace. Its existing saved version remains. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.UpdateDocumentTemplate' \ -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 '{ "template_id": "c_template_proposal", "level": "user" }' ``` #### 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/documents.UpdateDocumentTemplate", { 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({ "template_id": "c_template_proposal", "level": "user" }), }); 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 = { "template_id": "c_template_proposal", "level": "user" } request = Request( "https://api.brigg.app/v1/operations/documents.UpdateDocumentTemplate", 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, "published": false } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "template_id": { "type": "string", "minLength": 1, "description": "Use a template_id from the template catalogue; this is not the ID of a generated document. [workspace.ListTemplates](/developers/reference/workspace/ListTemplates)." }, "label": { "type": "string", "minLength": 1, "maxLength": 200, "description": "New display name for the template. Omit to preserve the name; this does not edit its document content or fields." }, "level": { "type": "string", "enum": [ "org", "user" ], "description": "org shares with the workspace; user returns it to its original creator when that person is still a member, otherwise to the acting member. Omit to preserve sharing." } }, "required": [ "template_id" ], "additionalProperties": false, "examples": [ { "template_id": "c_template_proposal", "label": "Project proposal" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "The requested metadata changes were saved." }, "published": { "type": "boolean", "description": "True only when this sharing change created an initial saved content version so colleagues can render the template. False for a rename, making it private, or sharing a template that already had a saved version. This is not a current-publication or public-web visibility flag." } }, "required": [ "ok", "published" ], "additionalProperties": false, "examples": [ { "ok": true, "published": false } ] } ``` --- # Update document template field Update the instruction for a template field, or the layout of an inserted document, using its stable field_id. This edits a draft; save it in Brigg before generating documents from the new version. POST https://api.brigg.app/v1/operations/documents.UpdateDocumentTemplateField ## Access & visibility Allow `documents.UpdateDocumentTemplateField` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `template_id` | string | Yes | Use a template_id from the template catalogue; this is not the ID of a generated document. [workspace.ListTemplates](/developers/reference/workspace/ListTemplates). At least 1 character. | | `field_id` | string | Yes | Exact field_id from items or inserts in ListDocumentTemplateFields for this same template_id. It is a stable name, not an array index, display label or file ID. Pattern: `^[a-z0-9][a-z0-9-]{0,63}$`. | | `instruction` | string | No | New generation instruction for a generated field. Omit to retain it. This has no effect on an inserted document. At least 1 character. At most 500 characters. | | `layout` | string | No | New presentation layout for an inserted text document. Omit to retain it. This has no effect on a generated field. Allowed: `"one-column"`, `"two-column"`, `"compact"`. | ## Inspect, edit, then inspect again Use [List document template fields](/developers/reference/documents/ListDocumentTemplateFields) to get this template's generated fields, inserted documents and placement landmarks. A generated field contains an instruction; an insert references an existing text document. Use the returned field_id names and landmark_id values exactly. Edits create a new template version and require template-management authority, not just read access. Pending or completed signing can lock the template. Existing generated documents are not regenerated by a template edit. The returned version_id records the changed template; it is not a precondition for another edit. Re-list before selecting a placement in the changed structure. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | | `version_id` | string | Yes | New template version containing this edit. It is not a collaborative text-document version or an optimistic-lock token. Re-list template fields to inspect the current structure after the edit. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | | 409 | `signing_locked` | Pending or completed signing protects this template. Do not retry the edit unchanged. | | 400 | `not_a_template` | Choose a document template from ListTemplates, not a generated document. | | 404 | `no_active_version` | This template has no editable version. Open it in Brigg to complete its setup. | | 404 | `slot_not_found` | Re-list this template's fields and inserts; use an exact current field_id. | ## Next steps - [List document template fields](/developers/reference/documents/ListDocumentTemplateFields) - [Add document template field](/developers/reference/documents/AddDocumentTemplateField) - [Remove document template field](/developers/reference/documents/RemoveDocumentTemplateField) - [List templates](/developers/reference/workspace/ListTemplates) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Change a generation instruction Choose a field from items, not inserts. Its identity and placement stay the same. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.UpdateDocumentTemplateField' \ -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 '{ "template_id": "c_template_proposal", "field_id": "project-summary", "instruction": "Summarize the agreed deliverables in three bullet points." }' ``` #### 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/documents.UpdateDocumentTemplateField", { 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({ "template_id": "c_template_proposal", "field_id": "project-summary", "instruction": "Summarize the agreed deliverables in three bullet points." }), }); 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 = { "template_id": "c_template_proposal", "field_id": "project-summary", "instruction": "Summarize the agreed deliverables in three bullet points." } request = Request( "https://api.brigg.app/v1/operations/documents.UpdateDocumentTemplateField", 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, "version_id": "v_proposal_4" } ``` ### Change inserted terms layout Choose an insert from inserts. This does not change the underlying text document. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.UpdateDocumentTemplateField' \ -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 '{ "template_id": "c_template_proposal", "field_id": "terms", "layout": "compact" }' ``` #### 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/documents.UpdateDocumentTemplateField", { 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({ "template_id": "c_template_proposal", "field_id": "terms", "layout": "compact" }), }); 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 = { "template_id": "c_template_proposal", "field_id": "terms", "layout": "compact" } request = Request( "https://api.brigg.app/v1/operations/documents.UpdateDocumentTemplateField", 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, "version_id": "v_proposal_4" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "template_id": { "type": "string", "minLength": 1, "description": "Use a template_id from the template catalogue; this is not the ID of a generated document. [workspace.ListTemplates](/developers/reference/workspace/ListTemplates)." }, "field_id": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]{0,63}$", "description": "Exact field_id from items or inserts in ListDocumentTemplateFields for this same template_id. It is a stable name, not an array index, display label or file ID." }, "instruction": { "type": "string", "minLength": 1, "maxLength": 500, "description": "New generation instruction for a generated field. Omit to retain it. This has no effect on an inserted document." }, "layout": { "type": "string", "enum": [ "one-column", "two-column", "compact" ], "description": "New presentation layout for an inserted text document. Omit to retain it. This has no effect on a generated field." } }, "required": [ "template_id", "field_id" ], "additionalProperties": false, "examples": [ { "template_id": "c_template_proposal", "field_id": "project-summary", "instruction": "Summarize the agreed deliverables in three bullet points." } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." }, "version_id": { "type": "string", "description": "New template version containing this edit. It is not a collaborative text-document version or an optimistic-lock token. Re-list template fields to inspect the current structure after the edit." } }, "required": [ "ok", "version_id" ], "additionalProperties": false, "examples": [ { "ok": true, "version_id": "v_proposal_4" } ] } ``` --- # Get document Inspect a document by its file ID: its kind, location and supported reads and exports. Capabilities describe what the acting member can do now; each later call checks access again. POST https://api.brigg.app/v1/operations/documents.GetDocument ## Access & visibility Allow `documents.GetDocument` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `file_id` | string | Yes | Stable file_id from ListDocuments, SearchDocuments, CompleteUpload or a document creation result. The same identity works across all document kinds. At least 1 character. | ## Choose the next operation Use `kind` and `capabilities` to choose a supported action. For an uploaded original, use [Get file download](/developers/reference/documents/GetFileDownload) directly or export as `original`. For collaborative text, [Read text document](/developers/reference/documents/ReadTextDocument) returns Markdown and a revision for safe editing. Generated documents export as PDF or Word. These capabilities describe the document under the current credential and selected data scope. Your API key also needs the next operation’s grant; capabilities never grant it. Internal source files and authoring commands are not exposed. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `file_id` | string | Yes | The requested document's stable identity. Exports do not replace this source document. | | `kind` | string | Yes | file is an uploaded original; text_document is collaborative Markdown; generated_document is a rendered Brigg document. Allowed: `"file"`, `"text_document"`, `"generated_document"`. | | `filename` | string | Yes | Current document name. Text and generated documents need not have a filename extension. | | `scope` | string or null | Yes | Current document collection: org is workspace-shared, user is personal, and resources is the resources collection. Null means no collection is recorded; it does not grant access. This is location metadata, not a request to move the document. | | `path` | string | Yes | Folder path within the collection; empty means its root. | | `content_type` | string or null | Yes | Original upload media type. Null for text and generated documents, whose export format determines their media type. | | `size_bytes` | number or null | Yes | Original upload byte length, or null when no original binary exists. Read the export result for its byte length. | | `scan_status` | string or null | Yes | Malware scan state. Threats and failed scans block downloads. An unsupported file cannot be processed; only its original uploader can retrieve it as a forced download. Null is not proof of readiness. | | `created_at` | number | Yes | Creation time in Unix milliseconds. | | `created_by` | string or null | Yes | Account that created the record, or null when no account is recorded. | | `owner_account_id` | string or null | Yes | Member who owns a private document, or null for a shared document. Access is still checked independently of this metadata. | | `entry_id` | string or null | Yes | Attached record ID, or null when no record is associated. | | `capabilities` | [object](#response-capabilities) | Yes | Supported public reads and exports under the current credential and selected data scope; these are advisory and never grant permissions. | ### response.capabilities | Field | Type | Required | Description | | --- | --- | --- | --- | | `read` | [object](#response-capabilities-read) or null | Yes | Non-null only when current Markdown can be read with ReadTextDocument. Null does not mean the original file cannot be downloaded. | | `export` | [object](#response-capabilities-export) | Yes | Formats and revision selections that ExportDocument currently supports for this source. | | `unavailable` | string or null | Yes | scan_blocked means the original bytes are blocked; collab_unavailable means live collaborative content is unavailable. Null means neither condition applies. An explicit historical text version may still be exportable without live collaboration. | ### response.capabilities.read | Field | Type | Required | Description | | --- | --- | --- | --- | | `format` | string | Yes | markdown identifies collaborative text readable through ReadTextDocument. Always `"markdown"`. | ### response.capabilities.export | Field | Type | Required | Description | | --- | --- | --- | --- | | `formats` | array of string | Yes | Formats currently supported by ExportDocument for this document. original preserves uploaded bytes; md, pdf and docx render supported content. An empty list means export is unavailable. Each item: `"original"`, `"md"`, `"pdf"`, `"docx"`. | | `revisions` | array of string | Yes | saved selects the saved state; current includes the acting member’s own generated draft; version means an accessible saved version ID can be supplied. These are available selections, not version IDs. Each item: `"saved"`, `"current"`, `"version"`. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The file does not exist or is not visible to this acting member. A known ID does not grant access. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [List documents](/developers/reference/documents/ListDocuments) - [Export document](/developers/reference/documents/ExportDocument) - [Read text document](/developers/reference/documents/ReadTextDocument) - [Get file download](/developers/reference/documents/GetFileDownload) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Inspect a text document The same file_id is used to read, edit and export this document. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.GetDocument' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "file_id": "f_project_notes" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/documents.GetDocument", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "file_id": "f_project_notes" }), }); 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 payload = { "file_id": "f_project_notes" } request = Request( "https://api.brigg.app/v1/operations/documents.GetDocument", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "file_id": "f_project_notes", "kind": "text_document", "filename": "Project notes", "scope": "org", "path": "Projects", "content_type": null, "size_bytes": null, "scan_status": null, "created_at": 1794301200000, "created_by": "a_alex", "owner_account_id": null, "entry_id": null, "capabilities": { "read": { "format": "markdown" }, "export": { "formats": [ "md", "pdf", "docx" ], "revisions": [ "saved", "current", "version" ] }, "unavailable": null } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "file_id": { "type": "string", "minLength": 1, "description": "Stable file_id from ListDocuments, SearchDocuments, CompleteUpload or a document creation result. The same identity works across all document kinds." } }, "required": [ "file_id" ], "additionalProperties": false, "examples": [ { "file_id": "f_project_notes" } ] } ``` ```json-schema-response { "type": "object", "properties": { "file_id": { "type": "string", "description": "The requested document's stable identity. Exports do not replace this source document." }, "kind": { "type": "string", "enum": [ "file", "text_document", "generated_document" ], "description": "file is an uploaded original; text_document is collaborative Markdown; generated_document is a rendered Brigg document." }, "filename": { "type": "string", "description": "Current document name. Text and generated documents need not have a filename extension." }, "scope": { "type": [ "string", "null" ], "description": "Current document collection: org is workspace-shared, user is personal, and resources is the resources collection. Null means no collection is recorded; it does not grant access. This is location metadata, not a request to move the document." }, "path": { "type": "string", "description": "Folder path within the collection; empty means its root." }, "content_type": { "type": [ "string", "null" ], "description": "Original upload media type. Null for text and generated documents, whose export format determines their media type." }, "size_bytes": { "type": [ "number", "null" ], "description": "Original upload byte length, or null when no original binary exists. Read the export result for its byte length." }, "scan_status": { "type": [ "string", "null" ], "description": "Malware scan state. Threats and failed scans block downloads. An unsupported file cannot be processed; only its original uploader can retrieve it as a forced download. Null is not proof of readiness." }, "created_at": { "type": "number", "description": "Creation time in Unix milliseconds." }, "created_by": { "type": [ "string", "null" ], "description": "Account that created the record, or null when no account is recorded." }, "owner_account_id": { "type": [ "string", "null" ], "description": "Member who owns a private document, or null for a shared document. Access is still checked independently of this metadata." }, "entry_id": { "type": [ "string", "null" ], "description": "Attached record ID, or null when no record is associated." }, "capabilities": { "type": "object", "properties": { "read": { "type": [ "object", "null" ], "properties": { "format": { "type": "string", "const": "markdown", "description": "markdown identifies collaborative text readable through ReadTextDocument." } }, "additionalProperties": false, "required": [ "format" ], "description": "Non-null only when current Markdown can be read with ReadTextDocument. Null does not mean the original file cannot be downloaded." }, "export": { "type": "object", "properties": { "formats": { "type": "array", "items": { "type": "string", "enum": [ "original", "md", "pdf", "docx" ] }, "description": "Formats currently supported by ExportDocument for this document. original preserves uploaded bytes; md, pdf and docx render supported content. An empty list means export is unavailable." }, "revisions": { "type": "array", "items": { "type": "string", "enum": [ "saved", "current", "version" ] }, "description": "saved selects the saved state; current includes the acting member’s own generated draft; version means an accessible saved version ID can be supplied. These are available selections, not version IDs." } }, "required": [ "formats", "revisions" ], "additionalProperties": false, "description": "Formats and revision selections that ExportDocument currently supports for this source." }, "unavailable": { "type": [ "string", "null" ], "description": "scan_blocked means the original bytes are blocked; collab_unavailable means live collaborative content is unavailable. Null means neither condition applies. An explicit historical text version may still be exportable without live collaboration." } }, "required": [ "read", "export", "unavailable" ], "additionalProperties": false, "description": "Supported public reads and exports under the current credential and selected data scope; these are advisory and never grant permissions." } }, "required": [ "file_id", "kind", "filename", "scope", "path", "content_type", "size_bytes", "scan_status", "created_at", "created_by", "owner_account_id", "entry_id", "capabilities" ], "additionalProperties": false, "examples": [ { "file_id": "f_project_notes", "kind": "text_document", "filename": "Project notes", "scope": "org", "path": "Projects", "content_type": null, "size_bytes": null, "scan_status": null, "created_at": 1794301200000, "created_by": "a_alex", "owner_account_id": null, "entry_id": null, "capabilities": { "read": { "format": "markdown" }, "export": { "formats": [ "md", "pdf", "docx" ], "revisions": [ "saved", "current", "version" ] }, "unavailable": null } } ] } ``` --- # List documents List the files in one document folder. items contains files; folders contains the immediate subfolders. Use an empty path for the collection root. Personal collections are available only to their owner. POST https://api.brigg.app/v1/operations/documents.ListDocuments ## Access & visibility Allow `documents.ListDocuments` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `scope` | string | Yes | Document collection: org is shared with the workspace; user is private to the calling person; resources contains the workspace's supplied resources. A move changes who can read the document; omit scope when only changing its folder. Allowed: `"org"`, `"user"`, `"resources"`. | | `path` | string | No | Folder path within the selected document collection. An empty string is its root. Default: `""`. At most 1024 characters. | ## Response Returns **200 OK** with a JSON body. This operation has no continuation cursor. An empty `items` array means no matching visible results were returned. | Field | Type | Required | Description | | --- | --- | --- | --- | | `path` | string | Yes | Folder path within the selected document collection. An empty string is its root. | | `folders` | array of [object](#response-folders) | Yes | Immediate subfolders of the requested document location. | | `items` | array of [Document](#document-response-items) | Yes | Documents immediately inside the selected collection and folder; child folders are returned separately in folders. This operation has no cursor pagination. | ### response.folders[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Display name. | | `path` | string | Yes | Folder path within the selected document collection. An empty string is its root. | | `label` | string | No | Human-readable name for this content or saved version. | ### Document · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `file_id` | string | Yes | Stable file ID returned by documents.CompleteUpload, documents.ListDocuments or a document creation operation. Use the same ID for downloads, attachments and supported file-based workflows. Do not use a filename or storage path. | | `filename` | string | Yes | Original filename, including its extension. | | `size_bytes` | number or null | Yes | File size in bytes. Null for a document without a downloadable binary file. | | `content_type` | string or null | Yes | Media type of the file, such as application/pdf. Null when no binary file exists. | | `path` | string | Yes | Folder path within the selected document collection. An empty string is its root. | | `created_at` | number | Yes | Creation time in Unix milliseconds. | | `owner_account_id` | string or null | Yes | Account that owns a private document, or null for a workspace document. | | `created_by` | string or null | Yes | Account that created the record, or null when no account is recorded. | | `kind` | string or null | Yes | Document origin or format: user_upload, agent_generated, signed_document and other file categories; text_document identifies collaborative text, while document identifies a generated Brigg document. | | `scan_status` | string or null | Yes | Malware scan state. Threats and failed scans block downloads. An unsupported file cannot be processed; only its original uploader can retrieve it as a forced download. Null is not proof of readiness. | | `document_kind` | string | Yes | `file` = an uploaded file (its original bytes); `text_document` = a collaborative Tekstdokument (markdown); `generated_document` = a formatted document Brigg generated («Lag dokument»). Allowed: `"file"`, `"text_document"`, `"generated_document"`. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [Upload and download files](/developers/files) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.ListDocuments' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "scope": "org" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/documents.ListDocuments", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "scope": "org" }), }); 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 payload = { "scope": "org" } request = Request( "https://api.brigg.app/v1/operations/documents.ListDocuments", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "path": "Proposals", "folders": [], "items": [ { "file_id": "file_proposal", "filename": "Proposal.pdf", "size_bytes": 48231, "content_type": "application/pdf", "path": "Proposals", "created_at": 1794301200000, "owner_account_id": null, "created_by": "account_alex", "kind": "user_upload", "scan_status": "clean", "document_kind": "file" } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "scope": { "type": "string", "enum": [ "org", "user", "resources" ], "description": "Document collection: org is shared with the workspace; user is private to the calling person; resources contains the workspace's supplied resources. A move changes who can read the document; omit scope when only changing its folder." }, "path": { "type": "string", "maxLength": 1024, "default": "", "description": "Folder path within the selected document collection. An empty string is its root." } }, "required": [ "scope" ], "additionalProperties": false, "examples": [ { "scope": "org" } ] } ``` ```json-schema-response { "type": "object", "properties": { "path": { "type": "string", "description": "Folder path within the selected document collection. An empty string is its root." }, "folders": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string", "description": "Display name." }, "path": { "type": "string", "description": "Folder path within the selected document collection. An empty string is its root." }, "label": { "type": "string", "description": "Human-readable name for this content or saved version." } }, "required": [ "name", "path" ], "additionalProperties": false }, "description": "Immediate subfolders of the requested document location." }, "items": { "type": "array", "items": { "type": "object", "properties": { "file_id": { "type": "string", "description": "Stable file ID returned by documents.CompleteUpload, documents.ListDocuments or a document creation operation. Use the same ID for downloads, attachments and supported file-based workflows. Do not use a filename or storage path.", "examples": [ "file_proposal" ] }, "filename": { "type": "string", "examples": [ "Proposal.pdf" ], "description": "Original filename, including its extension." }, "size_bytes": { "type": [ "number", "null" ], "description": "File size in bytes. Null for a document without a downloadable binary file.", "examples": [ 48231 ] }, "content_type": { "type": [ "string", "null" ], "description": "Media type of the file, such as application/pdf. Null when no binary file exists.", "examples": [ "application/pdf" ] }, "path": { "type": "string", "description": "Folder path within the selected document collection. An empty string is its root.", "examples": [ "Proposals" ] }, "created_at": { "type": "number", "description": "Creation time in Unix milliseconds." }, "owner_account_id": { "type": [ "string", "null" ], "description": "Account that owns a private document, or null for a workspace document.", "examples": [ null ] }, "created_by": { "type": [ "string", "null" ], "examples": [ "account_alex" ], "description": "Account that created the record, or null when no account is recorded." }, "kind": { "type": [ "string", "null" ], "description": "Document origin or format: user_upload, agent_generated, signed_document and other file categories; text_document identifies collaborative text, while document identifies a generated Brigg document.", "examples": [ "user_upload" ] }, "scan_status": { "type": [ "string", "null" ], "description": "Malware scan state. Threats and failed scans block downloads. An unsupported file cannot be processed; only its original uploader can retrieve it as a forced download. Null is not proof of readiness.", "examples": [ "clean" ] }, "document_kind": { "type": "string", "enum": [ "file", "text_document", "generated_document" ], "description": "`file` = an uploaded file (its original bytes); `text_document` = a collaborative Tekstdokument (markdown); `generated_document` = a formatted document Brigg generated («Lag dokument»).", "examples": [ "file" ] } }, "required": [ "file_id", "filename", "size_bytes", "content_type", "path", "created_at", "owner_account_id", "created_by", "kind", "scan_status", "document_kind" ], "additionalProperties": false, "title": "Document" }, "description": "Documents immediately inside the selected collection and folder; child folders are returned separately in folders. This operation has no cursor pagination." } }, "required": [ "path", "folders", "items" ], "additionalProperties": false, "examples": [ { "path": "Proposals", "folders": [], "items": [ { "file_id": "file_proposal", "filename": "Proposal.pdf", "size_bytes": 48231, "content_type": "application/pdf", "path": "Proposals", "created_at": 1794301200000, "owner_account_id": null, "created_by": "account_alex", "kind": "user_upload", "scan_status": "clean", "document_kind": "file" } ] } ] } ``` --- # Search document content Search the text of readable files and return matching excerpts and file IDs. Results may combine keyword and semantic matching; scores are relative to this search, not percentages. POST https://api.brigg.app/v1/operations/documents.SearchDocumentContent ## Access & visibility Allow `documents.SearchDocumentContent` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `query` | string | Yes | Text to search for. At least 1 character. At most 400 characters. | | `limit` | integer | No | Maximum number of matching results to return. This operation does not provide a continuation cursor. Range: 1 to 50. | ## Response Returns **200 OK** with a JSON body. This operation has no continuation cursor. An empty `items` array means no matching visible results were returned. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [Document search result](#document-search-result-response-items) | Yes | Content matches in documents visible to the caller, bounded by limit. This operation has no cursor pagination. | ### Document search result · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `file_id` | null or string | Yes | Stable file ID returned by documents.CompleteUpload, documents.ListDocuments or a document creation operation. Use the same ID for downloads, attachments and supported file-based workflows. Do not use a filename or storage path. | | `filename` | null or string | Yes | Original filename, including its extension. | | `scope` | null or string | Yes | Document collection containing this match: org, user or resources. | | `path` | null or string | Yes | Folder path within the selected document collection. An empty string is its root. | | `snippet` | string | Yes | A short excerpt showing why the result matched. | | `score` | number | Yes | Search relevance score; use it for ranking results within this response, not as a probability. | | `channels` | array of string | Yes | Search methods that contributed to this match. Each item: `"keyword"`, `"semantic"`. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [Upload and download files](/developers/files) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.SearchDocumentContent' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "query": "onboarding" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/documents.SearchDocumentContent", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "query": "onboarding" }), }); 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 payload = { "query": "onboarding" } request = Request( "https://api.brigg.app/v1/operations/documents.SearchDocumentContent", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "file_id": "file_proposal", "filename": "Proposal.pdf", "scope": "org", "path": "Proposals", "snippet": "The project includes onboarding and support.", "score": 0.82, "channels": [] } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "query": { "type": "string", "minLength": 1, "maxLength": 400, "description": "Text to search for." }, "limit": { "type": "integer", "minimum": 1, "maximum": 50, "description": "Maximum number of matching results to return. This operation does not provide a continuation cursor." } }, "required": [ "query" ], "additionalProperties": false, "examples": [ { "query": "onboarding" } ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "title": "Document search result", "type": "object", "properties": { "file_id": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Stable file ID returned by documents.CompleteUpload, documents.ListDocuments or a document creation operation. Use the same ID for downloads, attachments and supported file-based workflows. Do not use a filename or storage path.", "examples": [ "file_proposal" ] }, "filename": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Original filename, including its extension.", "examples": [ "Proposal.pdf" ] }, "scope": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Document collection containing this match: org, user or resources.", "examples": [ "org" ] }, "path": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Folder path within the selected document collection. An empty string is its root.", "examples": [ "Proposals" ] }, "snippet": { "type": "string", "description": "A short excerpt showing why the result matched.", "examples": [ "The project includes onboarding and support." ] }, "score": { "type": "number", "description": "Search relevance score; use it for ranking results within this response, not as a probability.", "examples": [ 0.82 ] }, "channels": { "type": "array", "items": { "type": "string", "enum": [ "keyword", "semantic" ] }, "description": "Search methods that contributed to this match." } }, "required": [ "file_id", "filename", "scope", "path", "snippet", "score", "channels" ], "additionalProperties": false }, "description": "Content matches in documents visible to the caller, bounded by limit. This operation has no cursor pagination." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "file_id": "file_proposal", "filename": "Proposal.pdf", "scope": "org", "path": "Proposals", "snippet": "The project includes onboarding and support.", "score": 0.82, "channels": [] } ] } ] } ``` --- # Search documents Find readable files by a case-insensitive filename match, optionally within a folder. Use SearchDocumentContent to search the text inside documents. POST https://api.brigg.app/v1/operations/documents.SearchDocuments ## Access & visibility Allow `documents.SearchDocuments` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `scope` | string | Yes | Document collection: org is shared with the workspace; user is private to the calling person; resources contains the workspace's supplied resources. A move changes who can read the document; omit scope when only changing its folder. Allowed: `"org"`, `"user"`, `"resources"`. | | `query` | string | Yes | Text to search for. At least 1 character. At most 200 characters. | | `path_prefix` | string | No | Folder-path prefix used to narrow the search. | | `limit` | integer | No | Maximum number of matching results to return. This operation does not provide a continuation cursor. Maximum: 200. Greater than 0. | ## Response Returns **200 OK** with a JSON body. This operation has no continuation cursor. An empty `items` array means no matching visible results were returned. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [Document](#document-response-items) | Yes | Documents matching the search text in the selected collection and optional folder prefix, bounded by limit. This operation has no cursor pagination. | ### Document · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `file_id` | string | Yes | Stable file ID returned by documents.CompleteUpload, documents.ListDocuments or a document creation operation. Use the same ID for downloads, attachments and supported file-based workflows. Do not use a filename or storage path. | | `filename` | string | Yes | Original filename, including its extension. | | `size_bytes` | number or null | Yes | File size in bytes. Null for a document without a downloadable binary file. | | `content_type` | string or null | Yes | Media type of the file, such as application/pdf. Null when no binary file exists. | | `path` | string | Yes | Folder path within the selected document collection. An empty string is its root. | | `created_at` | number | Yes | Creation time in Unix milliseconds. | | `owner_account_id` | string or null | Yes | Account that owns a private document, or null for a workspace document. | | `created_by` | string or null | Yes | Account that created the record, or null when no account is recorded. | | `kind` | string or null | Yes | Document origin or format: user_upload, agent_generated, signed_document and other file categories; text_document identifies collaborative text, while document identifies a generated Brigg document. | | `scan_status` | string or null | Yes | Malware scan state. Threats and failed scans block downloads. An unsupported file cannot be processed; only its original uploader can retrieve it as a forced download. Null is not proof of readiness. | | `document_kind` | string | Yes | `file` = an uploaded file (its original bytes); `text_document` = a collaborative Tekstdokument (markdown); `generated_document` = a formatted document Brigg generated («Lag dokument»). Allowed: `"file"`, `"text_document"`, `"generated_document"`. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [Upload and download files](/developers/files) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.SearchDocuments' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "scope": "org", "query": "onboarding" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/documents.SearchDocuments", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "scope": "org", "query": "onboarding" }), }); 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 payload = { "scope": "org", "query": "onboarding" } request = Request( "https://api.brigg.app/v1/operations/documents.SearchDocuments", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "file_id": "file_proposal", "filename": "Proposal.pdf", "size_bytes": 48231, "content_type": "application/pdf", "path": "Proposals", "created_at": 1794301200000, "owner_account_id": null, "created_by": "account_alex", "kind": "user_upload", "scan_status": "clean", "document_kind": "file" } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "scope": { "type": "string", "enum": [ "org", "user", "resources" ], "description": "Document collection: org is shared with the workspace; user is private to the calling person; resources contains the workspace's supplied resources. A move changes who can read the document; omit scope when only changing its folder." }, "query": { "type": "string", "minLength": 1, "maxLength": 200, "description": "Text to search for." }, "path_prefix": { "type": "string", "description": "Folder-path prefix used to narrow the search." }, "limit": { "type": "integer", "exclusiveMinimum": 0, "maximum": 200, "description": "Maximum number of matching results to return. This operation does not provide a continuation cursor." } }, "required": [ "scope", "query" ], "additionalProperties": false, "examples": [ { "scope": "org", "query": "onboarding" } ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "file_id": { "type": "string", "description": "Stable file ID returned by documents.CompleteUpload, documents.ListDocuments or a document creation operation. Use the same ID for downloads, attachments and supported file-based workflows. Do not use a filename or storage path.", "examples": [ "file_proposal" ] }, "filename": { "type": "string", "examples": [ "Proposal.pdf" ], "description": "Original filename, including its extension." }, "size_bytes": { "type": [ "number", "null" ], "description": "File size in bytes. Null for a document without a downloadable binary file.", "examples": [ 48231 ] }, "content_type": { "type": [ "string", "null" ], "description": "Media type of the file, such as application/pdf. Null when no binary file exists.", "examples": [ "application/pdf" ] }, "path": { "type": "string", "description": "Folder path within the selected document collection. An empty string is its root.", "examples": [ "Proposals" ] }, "created_at": { "type": "number", "description": "Creation time in Unix milliseconds." }, "owner_account_id": { "type": [ "string", "null" ], "description": "Account that owns a private document, or null for a workspace document.", "examples": [ null ] }, "created_by": { "type": [ "string", "null" ], "examples": [ "account_alex" ], "description": "Account that created the record, or null when no account is recorded." }, "kind": { "type": [ "string", "null" ], "description": "Document origin or format: user_upload, agent_generated, signed_document and other file categories; text_document identifies collaborative text, while document identifies a generated Brigg document.", "examples": [ "user_upload" ] }, "scan_status": { "type": [ "string", "null" ], "description": "Malware scan state. Threats and failed scans block downloads. An unsupported file cannot be processed; only its original uploader can retrieve it as a forced download. Null is not proof of readiness.", "examples": [ "clean" ] }, "document_kind": { "type": "string", "enum": [ "file", "text_document", "generated_document" ], "description": "`file` = an uploaded file (its original bytes); `text_document` = a collaborative Tekstdokument (markdown); `generated_document` = a formatted document Brigg generated («Lag dokument»).", "examples": [ "file" ] } }, "required": [ "file_id", "filename", "size_bytes", "content_type", "path", "created_at", "owner_account_id", "created_by", "kind", "scan_status", "document_kind" ], "additionalProperties": false, "title": "Document" }, "description": "Documents matching the search text in the selected collection and optional folder prefix, bounded by limit. This operation has no cursor pagination." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "file_id": "file_proposal", "filename": "Proposal.pdf", "size_bytes": 48231, "content_type": "application/pdf", "path": "Proposals", "created_at": 1794301200000, "owner_account_id": null, "created_by": "account_alex", "kind": "user_upload", "scan_status": "clean", "document_kind": "file" } ] } ] } ``` --- # Delete document Delete a document and its associated versions and share links. A document awaiting signatures cannot be deleted. Shared documents require the creator's or an administrator's permission. POST https://api.brigg.app/v1/operations/documents.DeleteDocument ## Access & visibility Allow `documents.DeleteDocument` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `scope` | string | No | The tree the document is in. Omit to take it from the document itself. Allowed: `"org"`, `"user"`, `"resources"`. | | `file_id` | string | Yes | Use a file_id returned by this listing or by CompleteUpload. It is not an upload ID, storage path or filename. [documents.ListDocuments](/developers/reference/documents/ListDocuments). At least 1 character. | ## Response Returns **200 OK** with a JSON body. This permanently removes the selected document, not just its folder placement. For collaborative text documents it also removes live editing state, version history and share links. For generated documents it deletes the backing content. There is no public undo; use MoveDocument when you only want another location. The acting member must have authority to administer the document. A signing lock protects pending and completed signed content. A fresh request for an already absent file returns not_found; retry a lost successful response with the original idempotency key. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `signing_locked` | A signing request protects this document from this change. Inspect its signing state in Brigg; completed signed records must not be destroyed. | ## Next steps - [List documents](/developers/reference/documents/ListDocuments) - [Move document](/developers/reference/documents/MoveDocument) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Delete one document Select the exact file_id from ListDocuments before this irreversible action. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.DeleteDocument' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "file_id": "f_obsolete_notes" }' ``` #### TypeScript ```typescript 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/documents.DeleteDocument", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "file_id": "f_obsolete_notes" }), }); 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 = { "file_id": "f_obsolete_notes" } request = Request( "https://api.brigg.app/v1/operations/documents.DeleteDocument", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "scope": { "type": "string", "enum": [ "org", "user", "resources" ], "description": "The tree the document is in. Omit to take it from the document itself." }, "file_id": { "type": "string", "minLength": 1, "description": "Use a file_id returned by this listing or by CompleteUpload. It is not an upload ID, storage path or filename. [documents.ListDocuments](/developers/reference/documents/ListDocuments)." } }, "required": [ "file_id" ], "additionalProperties": false, "examples": [ { "file_id": "f_obsolete_notes" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." } }, "required": [ "ok" ], "additionalProperties": false, "examples": [ { "ok": true } ] } ``` --- # Detach document Remove the link between a document and a record. A document referenced by a file field must instead be removed from that field. Attachments without another document location cannot be detached. POST https://api.brigg.app/v1/operations/documents.DetachDocument ## Access & visibility Allow `documents.DetachDocument` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `file_id` | string | Yes | Use a file_id returned by this listing or by CompleteUpload. It is not an upload ID, storage path or filename. [documents.ListDocuments](/developers/reference/documents/ListDocuments). At least 1 character. | | `entry_id` | string | Yes | Record ID returned by the relevant record create, get or list operation. The credential needs access to that record's resource type. At least 1 character. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [Upload and download files](/developers/files) - [List documents](/developers/reference/documents/ListDocuments) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.DetachDocument' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "file_id": "e_example", "entry_id": "e_example" }' ``` #### TypeScript ```typescript 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/documents.DetachDocument", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "file_id": "e_example", "entry_id": "e_example" }), }); 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 = { "file_id": "e_example", "entry_id": "e_example" } request = Request( "https://api.brigg.app/v1/operations/documents.DetachDocument", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "file_id": { "type": "string", "minLength": 1, "description": "Use a file_id returned by this listing or by CompleteUpload. It is not an upload ID, storage path or filename. [documents.ListDocuments](/developers/reference/documents/ListDocuments)." }, "entry_id": { "type": "string", "minLength": 1, "description": "Record ID returned by the relevant record create, get or list operation. The credential needs access to that record's resource type." } }, "required": [ "file_id", "entry_id" ], "additionalProperties": false, "examples": [ { "file_id": "e_example", "entry_id": "e_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." } }, "required": [ "ok" ], "additionalProperties": false, "examples": [ { "ok": true } ] } ``` --- # Export document Export an accessible document using its file ID. Download an uploaded file unchanged, or render a text or generated document in a supported format. The default is the saved state. The result identifies both the download file and the source revision. POST https://api.brigg.app/v1/operations/documents.ExportDocument ## Access & visibility Allow `documents.ExportDocument` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `file_id` | string | Yes | The source document's stable file_id from GetDocument, ListDocuments, SearchDocuments or CompleteUpload. No internal document or bundle ID is needed. At least 1 character. | | `format` | string | Yes | Choose from GetDocument.capabilities.export.formats: original returns an upload unchanged; md is available for text documents; pdf and docx render text or generated documents. Allowed: `"original"`, `"md"`, `"pdf"`, `"docx"`. | | `revision` | string | No | Omit for saved. current includes only the acting member’s own generated draft, otherwise the saved version. For exact historical content, pass an accessible version_id. A read/edit revision token is not a version ID. At least 1 character. At most 200 characters. | ## Export, then download Inspect [Get document](/developers/reference/documents/GetDocument) to choose a supported format. Send this command with an idempotency key, then pass the returned `file_id` to [Get file download](/developers/reference/documents/GetFileDownload). Download from its temporary URL without sending your API key to that URL. Reuse the same acting member throughout. The source is unchanged. `original` returns the existing uploaded file without copying or converting it. A rendered export is a separate private file; it is not automatically filed into a folder or shared with the source’s audience. A PDF upload cannot be converted to Word or Markdown by this operation. ## Choose the content to export For a generated document, the default `saved` means its published saved state, never a private draft. If there is no saved state, Brigg returns `no_saved_version`; choose `current` explicitly to export the acting member’s draft. Other members’ drafts are never selected. Collaborative text has no separate unsaved layer: `saved` and `current` both capture live content and require collaboration to be available. An explicit history `version_id` exports that state without silently falling back to different content. Use [List text document versions](/developers/reference/documents/ListTextDocumentVersions) to discover text history. Uploaded originals accept `saved` and `current` for the same verified bytes. An idempotent retry returns the same export. To capture later edits, make a new command with a new idempotency key. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `file_id` | string | Yes | File to download with GetFileDownload. For original, this equals the source file_id. Rendered exports create a separate private file owned by the acting member. | | `filename` | string | Yes | Download filename, including the extension for a rendered output. An original upload retains its filename. | | `content_type` | string or null | Yes | Media type of the downloadable output; null only when an older uploaded original has no recorded media type. | | `size_bytes` | number or null | Yes | Output byte length; null only when an older original has no recorded size. | | `source` | [object](#response-source) | Yes | Identity and exact captured state of the source document used for this export. | ### response.source | Field | Type | Required | Description | | --- | --- | --- | --- | | `file_id` | string | Yes | Stable identity of the source document, distinct from the rendered download's file_id. | | `kind` | string | Yes | Source document kind, independent of the chosen output format. Allowed: `"file"`, `"text_document"`, `"generated_document"`. | | `revision` | string or null | Yes | Opaque token identifying the captured source content. Null is possible for an older uploaded file. It is not a version selector. | | `version_id` | string or null | Yes | Accessible saved source version, if one was captured. Retain it with source.file_id to export that state later. Null means no historical version was identified. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/reliability). | HTTP status | Code | What to do | | --- | --- | --- | | 400 | `invalid_json` | Send a JSON object with Content-Type: application/json. | | 400 | `invalid_input` | Use saved, current or a valid saved version ID, not a read/edit revision token. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The source does not exist or is not visible to this acting member. | | 429 | `rate_limited` | Wait for Retry-After before retrying. Reuse the original Idempotency-Key. | | 422 | `unsupported_format` | Choose a format from details.supported, or inspect GetDocument again. A PDF upload cannot be converted to Word or Markdown. | | 422 | `unsupported_revision` | Choose a revision selection supported by this document. Uploaded originals have no historical version selector. | | 409 | `no_saved_version` | The generated document has no saved version. Save it in Brigg or explicitly choose current to export the acting member’s draft. | | 404 | `version_not_found` | That historical version is absent or inaccessible. Do not fall back to another revision without choosing to do so. | | 409 | `scan_blocked` | The original file is blocked by its scan result. Retrying unchanged does not unblock it. | | 409 | `collab_unavailable` | Live collaborative text is unavailable. Retry when collaboration is restored or deliberately select a known history version. | | 409 | `source_changed` | The source changed during rendering. Read its state again before requesting another export. | | 409 | `not_renderable` | This generated document has no renderable content. Open and save its content in Brigg before exporting. | ## Next steps - [Get document](/developers/reference/documents/GetDocument) - [Get file download](/developers/reference/documents/GetFileDownload) - [List text document versions](/developers/reference/documents/ListTextDocumentVersions) - [List documents](/developers/reference/documents/ListDocuments) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Render text as PDF Export the live saved content, then download the returned file_id. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.ExportDocument' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "file_id": "f_project_notes", "format": "pdf" }' ``` #### TypeScript ```typescript 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/documents.ExportDocument", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "file_id": "f_project_notes", "format": "pdf" }), }); 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 = { "file_id": "f_project_notes", "format": "pdf" } request = Request( "https://api.brigg.app/v1/operations/documents.ExportDocument", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "file_id": "f_project_notes_pdf", "filename": "Project notes.pdf", "content_type": "application/pdf", "size_bytes": 18432, "source": { "file_id": "f_project_notes", "kind": "text_document", "revision": "tdr_before_edit", "version_id": "tdv_a1b2c3d4" } } ``` ### Keep an uploaded original No conversion or copy is made. The download and source IDs are identical. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.ExportDocument' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "file_id": "f_agreement", "format": "original" }' ``` #### TypeScript ```typescript 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/documents.ExportDocument", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "file_id": "f_agreement", "format": "original" }), }); 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 = { "file_id": "f_agreement", "format": "original" } request = Request( "https://api.brigg.app/v1/operations/documents.ExportDocument", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "file_id": "f_agreement", "filename": "Agreement.pdf", "content_type": "application/pdf", "size_bytes": 48231, "source": { "file_id": "f_agreement", "kind": "file", "revision": "original_revision_1", "version_id": null } } ``` ### Export a saved text version Use a version_id discovered for this same file_id, not its current revision token. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.ExportDocument' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "file_id": "f_project_notes", "format": "md", "revision": "tdv_a1b2c3d4" }' ``` #### TypeScript ```typescript 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/documents.ExportDocument", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "file_id": "f_project_notes", "format": "md", "revision": "tdv_a1b2c3d4" }), }); 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 = { "file_id": "f_project_notes", "format": "md", "revision": "tdv_a1b2c3d4" } request = Request( "https://api.brigg.app/v1/operations/documents.ExportDocument", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "file_id": "f_project_notes_md", "filename": "Project notes.md", "content_type": "text/markdown; charset=utf-8", "size_bytes": 45, "source": { "file_id": "f_project_notes", "kind": "text_document", "revision": "tdr_before_edit", "version_id": "tdv_a1b2c3d4" } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "file_id": { "type": "string", "minLength": 1, "description": "The source document's stable file_id from GetDocument, ListDocuments, SearchDocuments or CompleteUpload. No internal document or bundle ID is needed." }, "format": { "type": "string", "enum": [ "original", "md", "pdf", "docx" ], "description": "Choose from GetDocument.capabilities.export.formats: original returns an upload unchanged; md is available for text documents; pdf and docx render text or generated documents." }, "revision": { "type": "string", "minLength": 1, "maxLength": 200, "description": "Omit for saved. current includes only the acting member’s own generated draft, otherwise the saved version. For exact historical content, pass an accessible version_id. A read/edit revision token is not a version ID." } }, "required": [ "format", "file_id" ], "additionalProperties": false, "examples": [ { "file_id": "f_project_notes", "format": "pdf" } ] } ``` ```json-schema-response { "type": "object", "properties": { "file_id": { "type": "string", "description": "File to download with GetFileDownload. For original, this equals the source file_id. Rendered exports create a separate private file owned by the acting member." }, "filename": { "type": "string", "description": "Download filename, including the extension for a rendered output. An original upload retains its filename." }, "content_type": { "type": [ "string", "null" ], "description": "Media type of the downloadable output; null only when an older uploaded original has no recorded media type." }, "size_bytes": { "type": [ "number", "null" ], "description": "Output byte length; null only when an older original has no recorded size." }, "source": { "type": "object", "properties": { "file_id": { "type": "string", "description": "Stable identity of the source document, distinct from the rendered download's file_id." }, "kind": { "type": "string", "enum": [ "file", "text_document", "generated_document" ], "description": "Source document kind, independent of the chosen output format." }, "revision": { "type": [ "string", "null" ], "description": "Opaque token identifying the captured source content. Null is possible for an older uploaded file. It is not a version selector." }, "version_id": { "type": [ "string", "null" ], "description": "Accessible saved source version, if one was captured. Retain it with source.file_id to export that state later. Null means no historical version was identified." } }, "required": [ "file_id", "kind", "revision", "version_id" ], "additionalProperties": false, "description": "Identity and exact captured state of the source document used for this export." } }, "required": [ "file_id", "filename", "content_type", "size_bytes", "source" ], "additionalProperties": false, "examples": [ { "file_id": "f_project_notes_pdf", "filename": "Project notes.pdf", "content_type": "application/pdf", "size_bytes": 18432, "source": { "file_id": "f_project_notes", "kind": "text_document", "revision": "tdr_before_edit", "version_id": "tdv_a1b2c3d4" } } ] } ``` --- # Move document Move a document between shared and personal storage or into a different folder. Documents awaiting signatures and system-managed resources cannot be moved. POST https://api.brigg.app/v1/operations/documents.MoveDocument ## Access & visibility Allow `documents.MoveDocument` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `file_id` | string | Yes | Use a file_id returned by this listing or by CompleteUpload. It is not an upload ID, storage path or filename. [documents.ListDocuments](/developers/reference/documents/ListDocuments). At least 1 character. | | `scope` | string | No | Destination collection: org shares with the workspace; user restores personal ownership. Omit to keep the current collection and change only its folder. The resources collection cannot be either end of a move. Allowed: `"org"`, `"user"`. | | `path` | string | No | Destination folder path. Omitted or empty means the destination collection's root, not the current folder. At most 1024 characters. | ## Moving can change who may read Keep file_id as the stable identity. Moving to org shares reading access with the workspace; moving to user returns the document to its recorded creator when that person is still active, otherwise to the acting member. It does not necessarily make the acting member the owner. The caller needs authority to administer the document. Supplying only path keeps its current collection; omit path only when you intend to move it to the root. Documents in resources cannot be moved, and a signing lock can prevent a scope change. Read [List documents](/developers/reference/documents/ListDocuments) afterwards using the resulting collection and path. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `file_id` | string | Yes | Stable file ID returned by documents.CompleteUpload, documents.ListDocuments or a document creation operation. Use the same ID for downloads, attachments and supported file-based workflows. Do not use a filename or storage path. | | `scope` | string | Yes | The resulting collection after the move. | | `path` | string | Yes | The resulting folder path; an empty string means the collection root. | | `published` | boolean | Yes | Whether moving this generated content into shared workspace scope also published it. This does not mean anonymous web access. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `signing_locked` | A signing request protects this document from this change. Inspect its signing state in Brigg; completed signed records must not be destroyed. | ## Next steps - [List documents](/developers/reference/documents/ListDocuments) - [Rename document](/developers/reference/documents/RenameDocument) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Move within its current collection This keeps visibility unchanged and moves the document into Projects/Agreements. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.MoveDocument' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "file_id": "f_agreement", "path": "Projects/Agreements" }' ``` #### TypeScript ```typescript 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/documents.MoveDocument", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "file_id": "f_agreement", "path": "Projects/Agreements" }), }); 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 = { "file_id": "f_agreement", "path": "Projects/Agreements" } request = Request( "https://api.brigg.app/v1/operations/documents.MoveDocument", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "file_id": "f_agreement", "scope": "org", "path": "Projects/Agreements", "published": false } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "file_id": { "type": "string", "minLength": 1, "description": "Use a file_id returned by this listing or by CompleteUpload. It is not an upload ID, storage path or filename. [documents.ListDocuments](/developers/reference/documents/ListDocuments)." }, "scope": { "type": "string", "enum": [ "org", "user" ], "description": "Destination collection: org shares with the workspace; user restores personal ownership. Omit to keep the current collection and change only its folder. The resources collection cannot be either end of a move." }, "path": { "type": "string", "maxLength": 1024, "description": "Destination folder path. Omitted or empty means the destination collection's root, not the current folder." } }, "required": [ "file_id" ], "additionalProperties": false, "examples": [ { "file_id": "f_agreement", "path": "Projects/Agreements" } ] } ``` ```json-schema-response { "type": "object", "properties": { "file_id": { "type": "string", "description": "Stable file ID returned by documents.CompleteUpload, documents.ListDocuments or a document creation operation. Use the same ID for downloads, attachments and supported file-based workflows. Do not use a filename or storage path." }, "scope": { "type": "string", "description": "The resulting collection after the move." }, "path": { "type": "string", "description": "The resulting folder path; an empty string means the collection root." }, "published": { "type": "boolean", "description": "Whether moving this generated content into shared workspace scope also published it. This does not mean anonymous web access." } }, "required": [ "file_id", "scope", "path", "published" ], "additionalProperties": false, "examples": [ { "file_id": "f_agreement", "scope": "org", "path": "Projects/Agreements", "published": false } ] } ``` --- # Rename document Rename a document without moving it. Documents awaiting signatures cannot be renamed. POST https://api.brigg.app/v1/operations/documents.RenameDocument ## Access & visibility Allow `documents.RenameDocument` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `scope` | string | No | The tree the document is in. Omit to take it from the document itself. Allowed: `"org"`, `"user"`, `"resources"`. | | `file_id` | string | Yes | Use a file_id returned by this listing or by CompleteUpload. It is not an upload ID, storage path or filename. [documents.ListDocuments](/developers/reference/documents/ListDocuments). At least 1 character. | | `filename` | string | Yes | New display filename after trimming surrounding spaces. Include the desired extension for an uploaded file. Renaming does not convert its format or change its bytes. At least 1 character. At most 255 characters. | ## Response Returns **200 OK** with a JSON body. The file stays in the same folder and keeps its file_id. Reading a shared document does not necessarily permit renaming it: the acting member must have authority to administer the document, such as its owner, responsible creator or a permitted workspace administrator. An existing signing lock prevents changes to a document's name. | Field | Type | Required | Description | | --- | --- | --- | --- | | `file_id` | string | Yes | The same stable identity supplied as file_id. This response uses camelCase; later requests still use file_id. | | `filename` | string | Yes | The resulting trimmed filename. Use this value when updating your display; the file identity has not changed. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `signing_locked` | A signing request protects this document from this change. Inspect its signing state in Brigg; completed signed records must not be destroyed. | | 400 | `scope_mismatch` | The supplied scope differs from the document's current collection. Read its location again or omit scope to resolve it from the document. | ## Next steps - [List documents](/developers/reference/documents/ListDocuments) - [Move document](/developers/reference/documents/MoveDocument) - [Get file download](/developers/reference/documents/GetFileDownload) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Rename in place Only the display filename changes; keep the same file ID. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.RenameDocument' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "file_id": "f_agreement", "filename": "Signed agreement.pdf" }' ``` #### TypeScript ```typescript 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/documents.RenameDocument", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "file_id": "f_agreement", "filename": "Signed agreement.pdf" }), }); 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 = { "file_id": "f_agreement", "filename": "Signed agreement.pdf" } request = Request( "https://api.brigg.app/v1/operations/documents.RenameDocument", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "file_id": "f_agreement", "filename": "Signed agreement.pdf" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "scope": { "type": "string", "enum": [ "org", "user", "resources" ], "description": "The tree the document is in. Omit to take it from the document itself." }, "file_id": { "type": "string", "minLength": 1, "description": "Use a file_id returned by this listing or by CompleteUpload. It is not an upload ID, storage path or filename. [documents.ListDocuments](/developers/reference/documents/ListDocuments)." }, "filename": { "type": "string", "minLength": 1, "maxLength": 255, "description": "New display filename after trimming surrounding spaces. Include the desired extension for an uploaded file. Renaming does not convert its format or change its bytes." } }, "required": [ "file_id", "filename" ], "additionalProperties": false, "examples": [ { "file_id": "f_agreement", "filename": "Signed agreement.pdf" } ] } ``` ```json-schema-response { "type": "object", "properties": { "file_id": { "type": "string", "description": "The same stable identity supplied as file_id. This response uses camelCase; later requests still use file_id." }, "filename": { "type": "string", "description": "The resulting trimmed filename. Use this value when updating your display; the file identity has not changed." } }, "required": [ "file_id", "filename" ], "additionalProperties": false, "examples": [ { "file_id": "f_agreement", "filename": "Signed agreement.pdf" } ] } ``` --- # Get file Read file metadata under the caller's current file and record permissions. This never returns a storage key or a download credential. POST https://api.brigg.app/v1/operations/documents.GetFile ## Access & visibility Allow `documents.GetFile` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `file_id` | string | Yes | Use a file_id returned by this listing or by CompleteUpload. It is not an upload ID, storage path or filename. [documents.ListDocuments](/developers/reference/documents/ListDocuments). At least 1 character. | ## Metadata, content and scan readiness This reads metadata only. Use [Get file download](/developers/reference/documents/GetFileDownload) to obtain a temporary binary download URL, or [Read text document](/developers/reference/documents/ReadTextDocument) for collaborative text content. `scan_status` can be `clean`, `threats_found`, `unsupported`, `failed` or null. Null means no verdict is recorded; it is **not** proof that the file is safe or ready. It can occur for content without a binary, legacy content, or a scan that has not reported yet. The download operation checks current readiness and access again. A threat, unsupported scan or failed scan is not fixed by retrying the same download in a tight loop. Use its returned error to distinguish pending work from a blocked file. Never infer that a non-null size or a successful metadata read authorizes access to bytes. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `file_id` | string | Yes | Stable file ID returned by documents.CompleteUpload, documents.ListDocuments or a document creation operation. Use the same ID for downloads, attachments and supported file-based workflows. Do not use a filename or storage path. | | `filename` | string | Yes | Original filename, including its extension. | | `content_type` | string or null | Yes | Media type of the file, such as application/pdf. Null when no binary file exists. | | `size_bytes` | number or null | Yes | File size in bytes. Null for a document without a downloadable binary file. | | `visibility` | string | Yes | Who may read the completed file. Personal files belong to the approved acting member; workspace files use shared access. Allowed: `"personal"`, `"workspace"`. | | `scan_status` | string or null | Yes | Recorded scan verdict: clean, threats_found, unsupported, failed, or null when no verdict is recorded. Null does not guarantee download readiness; GetFileDownload rechecks the current scan and permissions. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [Get file download](/developers/reference/documents/GetFileDownload) - [Read text document](/developers/reference/documents/ReadTextDocument) - [List documents](/developers/reference/documents/ListDocuments) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Uploaded PDF metadata A binary file with a recorded clean scan. Request a fresh download URL separately. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.GetFile' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "file_id": "f_agreement" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/documents.GetFile", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "file_id": "f_agreement" }), }); 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 payload = { "file_id": "f_agreement" } request = Request( "https://api.brigg.app/v1/operations/documents.GetFile", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "file_id": "f_agreement", "filename": "Agreement.pdf", "content_type": "application/pdf", "size_bytes": 48231, "visibility": "workspace", "scan_status": "clean" } ``` ### Document without binary metadata Null is unknown or inapplicable metadata, not a zero-byte PDF. Read collaborative content through ReadTextDocument when applicable. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.GetFile' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "file_id": "f_notes" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/documents.GetFile", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "file_id": "f_notes" }), }); 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 payload = { "file_id": "f_notes" } request = Request( "https://api.brigg.app/v1/operations/documents.GetFile", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "file_id": "f_notes", "filename": "Project notes", "content_type": null, "size_bytes": null, "visibility": "personal", "scan_status": null } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "file_id": { "type": "string", "minLength": 1, "description": "Use a file_id returned by this listing or by CompleteUpload. It is not an upload ID, storage path or filename. [documents.ListDocuments](/developers/reference/documents/ListDocuments)." } }, "required": [ "file_id" ], "additionalProperties": false, "examples": [ { "file_id": "f_agreement" } ] } ``` ```json-schema-response { "type": "object", "properties": { "file_id": { "type": "string", "description": "Stable file ID returned by documents.CompleteUpload, documents.ListDocuments or a document creation operation. Use the same ID for downloads, attachments and supported file-based workflows. Do not use a filename or storage path." }, "filename": { "type": "string", "description": "Original filename, including its extension." }, "content_type": { "type": [ "string", "null" ], "description": "Media type of the file, such as application/pdf. Null when no binary file exists." }, "size_bytes": { "type": [ "number", "null" ], "description": "File size in bytes. Null for a document without a downloadable binary file." }, "visibility": { "type": "string", "enum": [ "personal", "workspace" ], "description": "Who may read the completed file. Personal files belong to the approved acting member; workspace files use shared access." }, "scan_status": { "type": [ "string", "null" ], "description": "Recorded scan verdict: clean, threats_found, unsupported, failed, or null when no verdict is recorded. Null does not guarantee download readiness; GetFileDownload rechecks the current scan and permissions." } }, "required": [ "file_id", "filename", "content_type", "size_bytes", "visibility", "scan_status" ], "additionalProperties": false, "examples": [ { "file_id": "f_agreement", "filename": "Agreement.pdf", "content_type": "application/pdf", "size_bytes": 48231, "visibility": "workspace", "scan_status": "clean" } ] } ``` --- # Get file download Get a temporary download URL for a file the caller may currently read. The URL is pinned to the verified file version and expires after five minutes. POST https://api.brigg.app/v1/operations/documents.GetFileDownload ## Access & visibility Allow `documents.GetFileDownload` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `file_id` | string | Yes | Use a file_id returned by this listing or by CompleteUpload. It is not an upload ID, storage path or filename. [documents.ListDocuments](/developers/reference/documents/ListDocuments). At least 1 character. | ## Fetch the bytes The response is JSON containing a URL, not the file bytes. Make a separate GET request to url, for example `curl --fail --location "$DOWNLOAD_URL" --output agreement.pdf`. Do not forward your Brigg API key or member header to that host. Treat the URL as a short-lived credential. The URL identifies the verified version of this file and expires after five minutes. Request a new one if it expires before use. The [file guide](/developers/files) also provides a streaming server helper that performs both steps. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `url` | string | Yes | Temporary bearer URL for a GET request. Fetch it exactly as returned without the Brigg Authorization or Brigg-Act-As headers. Keep it out of logs and obtain another URL after expiry. | | `filename` | string | Yes | Current filename to use when saving the downloaded bytes. | | `expires_at` | number | Yes | Expiry time in Unix milliseconds. Obtain a fresh transfer or download URL after expiry. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | | 409 | `file_scan_blocked` | The file's scan prevents this download. Inspect details.scan_status. Do not repeatedly retry a threats_found, failed or unsupported verdict. Only the original uploader can retrieve an unsupported file as a forced download; it remains unavailable for processing. | ## Next steps - [Upload and download files](/developers/files) - [List documents](/developers/reference/documents/ListDocuments) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.GetFileDownload' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "file_id": "f_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/documents.GetFileDownload", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "file_id": "f_example" }), }); 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 payload = { "file_id": "f_example" } request = Request( "https://api.brigg.app/v1/operations/documents.GetFileDownload", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "url": "https://example.com/temporary-download", "filename": "Agreement.pdf", "expires_at": 1794301500000 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "file_id": { "type": "string", "minLength": 1, "description": "Use a file_id returned by this listing or by CompleteUpload. It is not an upload ID, storage path or filename. [documents.ListDocuments](/developers/reference/documents/ListDocuments)." } }, "required": [ "file_id" ], "additionalProperties": false, "examples": [ { "file_id": "f_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "url": { "type": "string", "description": "Temporary bearer URL for a GET request. Fetch it exactly as returned without the Brigg Authorization or Brigg-Act-As headers. Keep it out of logs and obtain another URL after expiry." }, "filename": { "type": "string", "description": "Current filename to use when saving the downloaded bytes." }, "expires_at": { "type": "number", "description": "Expiry time in Unix milliseconds. Obtain a fresh transfer or download URL after expiry." } }, "required": [ "url", "filename", "expires_at" ], "additionalProperties": false, "examples": [ { "url": "https://example.com/temporary-download", "filename": "Agreement.pdf", "expires_at": 1794301500000 } ] } ``` --- # Get upload Read the status of an upload created by this credential. The file ID becomes available after successful completion. POST https://api.brigg.app/v1/operations/documents.GetUpload ## Access & visibility Allow `documents.GetUpload` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `upload_id` | string | Yes | Keep the upload_id and the same credential and acting member throughout the upload. Completion returns a separate file_id. [documents.CreateUpload](/developers/reference/documents/CreateUpload). At least 1 character. | ## Where this fits in an upload The [file guide](/developers/files) includes a streaming Node.js helper and the complete HTTP sequence: create an upload, request a signed URL for each part, PUT the bytes directly to that URL, then complete the upload. Never send the Brigg API key to a transfer URL. Keep the same credential and acting member for every step. Follow the returned part size and count rather than imposing your own split. Completing with only `upload_id` lets Brigg collect part receipts. A successful byte transfer is not a completed file: verification and scanning must finish before you receive a usable `file_id`. Retain `upload_id` for recovery. Read its state before retransferring an interrupted upload; `ready` returns the existing file ID, while an expired upload requires a new start. Temporary transfer URLs and completed file IDs have different lifetimes. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `upload_id` | string | Yes | Upload ID returned by documents.CreateUpload. Only the credential that created this upload can transfer parts, complete it or cancel it. This is different from the completed file ID. | | `state` | string | Yes | Upload lifecycle state. Uploading bytes and completing the file are separate steps. Allowed: `"uploading"`, `"ready"`, `"cancelled"`, `"expired"`. | | `expires_at` | number | Yes | Upload expiry, in Unix milliseconds. Complete the upload before this time. | | `mode` | string | Yes | Transfer mode selected by Brigg: single upload or multipart upload. Follow the returned part count and part size. Allowed: `"single"`, `"multipart"`. | | `part_size` | integer | Yes | Bytes in each part, except the last part which contains the remaining bytes. Split the original file at these boundaries. | | `part_count` | integer | Yes | Number of parts to transfer before completion. One means the entire file is sent in a single PUT request. | | `file_id` | string | No | Stable file ID returned by documents.CompleteUpload, documents.ListDocuments or a document creation operation. Use the same ID for downloads, attachments and supported file-based workflows. Do not use a filename or storage path. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [Create upload](/developers/reference/documents/CreateUpload) - [Get upload part](/developers/reference/documents/GetUploadPart) - [Complete upload](/developers/reference/documents/CompleteUpload) - [Upload and download files](/developers/files) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.GetUpload' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "upload_id": "upl_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/documents.GetUpload", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "upload_id": "upl_example" }), }); 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 payload = { "upload_id": "upl_example" } request = Request( "https://api.brigg.app/v1/operations/documents.GetUpload", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "upload_id": "upl_example", "state": "uploading", "expires_at": 1794387600000, "mode": "single", "part_size": 48231, "part_count": 1 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "upload_id": { "type": "string", "minLength": 1, "description": "Keep the upload_id and the same credential and acting member throughout the upload. Completion returns a separate file_id. [documents.CreateUpload](/developers/reference/documents/CreateUpload)." } }, "required": [ "upload_id" ], "additionalProperties": false, "examples": [ { "upload_id": "upl_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "upload_id": { "type": "string", "description": "Upload ID returned by documents.CreateUpload. Only the credential that created this upload can transfer parts, complete it or cancel it. This is different from the completed file ID." }, "state": { "type": "string", "enum": [ "uploading", "ready", "cancelled", "expired" ], "description": "Upload lifecycle state. Uploading bytes and completing the file are separate steps." }, "expires_at": { "type": "number", "description": "Upload expiry, in Unix milliseconds. Complete the upload before this time." }, "mode": { "type": "string", "enum": [ "single", "multipart" ], "description": "Transfer mode selected by Brigg: single upload or multipart upload. Follow the returned part count and part size." }, "part_size": { "type": "integer", "description": "Bytes in each part, except the last part which contains the remaining bytes. Split the original file at these boundaries." }, "part_count": { "type": "integer", "description": "Number of parts to transfer before completion. One means the entire file is sent in a single PUT request." }, "file_id": { "type": "string", "description": "Stable file ID returned by documents.CompleteUpload, documents.ListDocuments or a document creation operation. Use the same ID for downloads, attachments and supported file-based workflows. Do not use a filename or storage path." } }, "required": [ "upload_id", "state", "expires_at", "mode", "part_size", "part_count" ], "additionalProperties": false, "examples": [ { "upload_id": "upl_example", "state": "uploading", "expires_at": 1794387600000, "mode": "single", "part_size": 48231, "part_count": 1 } ] } ``` --- # Get upload part Get a temporary PUT URL for one upload part. Use part 1 for a single upload. Request a new URL to retry an expired transfer; CompleteUpload collects multipart receipts for you. POST https://api.brigg.app/v1/operations/documents.GetUploadPart ## Access & visibility Allow `documents.GetUploadPart` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `upload_id` | string | Yes | Keep the upload_id and the same credential and acting member throughout the upload. Completion returns a separate file_id. [documents.CreateUpload](/developers/reference/documents/CreateUpload). At least 1 character. | | `part_number` | integer | Yes | One-based part number. Use 1 for a single upload; for multipart uploads, transfer every part from 1 through part_count. Greater than 0. | ## Where this fits in an upload The [file guide](/developers/files) includes a streaming Node.js helper and the complete HTTP sequence: create an upload, request a signed URL for each part, PUT the bytes directly to that URL, then complete the upload. Never send the Brigg API key to a transfer URL. Keep the same credential and acting member for every step. Follow the returned part size and count rather than imposing your own split. Completing with only `upload_id` lets Brigg collect part receipts. A successful byte transfer is not a completed file: verification and scanning must finish before you receive a usable `file_id`. Retain `upload_id` for recovery. Read its state before retransferring an interrupted upload; `ready` returns the existing file ID, while an expired upload requires a new start. Temporary transfer URLs and completed file IDs have different lifetimes. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `url` | string | Yes | Absolute URL, including its scheme. | | `method` | string | Yes | HTTP method to use when sending bytes to the temporary transfer URL. Allowed: `"PUT"`. | | `expires_at` | number | Yes | Expiry time in Unix milliseconds. Obtain a fresh transfer or download URL after expiry. | | `content_type` | string | Yes | Media type of the file, such as application/pdf. Null when no binary file exists. | | `size_bytes` | integer | Yes | File size in bytes. Null for a document without a downloadable binary file. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [Create upload](/developers/reference/documents/CreateUpload) - [Complete upload](/developers/reference/documents/CompleteUpload) - [Get upload](/developers/reference/documents/GetUpload) - [Upload and download files](/developers/files) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.GetUploadPart' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "upload_id": "upl_example", "part_number": 1 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/documents.GetUploadPart", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "upload_id": "upl_example", "part_number": 1 }), }); 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 payload = { "upload_id": "upl_example", "part_number": 1 } request = Request( "https://api.brigg.app/v1/operations/documents.GetUploadPart", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "url": "https://example.com/temporary-upload", "method": "PUT", "expires_at": 1794301800000, "content_type": "application/pdf", "size_bytes": 48231 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "upload_id": { "type": "string", "minLength": 1, "description": "Keep the upload_id and the same credential and acting member throughout the upload. Completion returns a separate file_id. [documents.CreateUpload](/developers/reference/documents/CreateUpload)." }, "part_number": { "type": "integer", "exclusiveMinimum": 0, "description": "One-based part number. Use 1 for a single upload; for multipart uploads, transfer every part from 1 through part_count." } }, "required": [ "upload_id", "part_number" ], "additionalProperties": false, "examples": [ { "upload_id": "upl_example", "part_number": 1 } ] } ``` ```json-schema-response { "type": "object", "properties": { "url": { "type": "string", "description": "Absolute URL, including its scheme." }, "method": { "type": "string", "enum": [ "PUT" ], "description": "HTTP method to use when sending bytes to the temporary transfer URL." }, "expires_at": { "type": "number", "description": "Expiry time in Unix milliseconds. Obtain a fresh transfer or download URL after expiry." }, "content_type": { "type": "string", "description": "Media type of the file, such as application/pdf. Null when no binary file exists." }, "size_bytes": { "type": "integer", "description": "File size in bytes. Null for a document without a downloadable binary file." } }, "required": [ "url", "method", "expires_at", "content_type", "size_bytes" ], "additionalProperties": false, "examples": [ { "url": "https://example.com/temporary-upload", "method": "PUT", "expires_at": 1794301800000, "content_type": "application/pdf", "size_bytes": 48231 } ] } ``` --- # Cancel upload Cancel an unfinished upload owned by this credential. Completed files must be removed through the document API. POST https://api.brigg.app/v1/operations/documents.CancelUpload ## Access & visibility Allow `documents.CancelUpload` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `upload_id` | string | Yes | Keep the upload_id and the same credential and acting member throughout the upload. Completion returns a separate file_id. [documents.CreateUpload](/developers/reference/documents/CreateUpload). At least 1 character. | ## Where this fits in an upload The [file guide](/developers/files) includes a streaming Node.js helper and the complete HTTP sequence: create an upload, request a signed URL for each part, PUT the bytes directly to that URL, then complete the upload. Never send the Brigg API key to a transfer URL. Keep the same credential and acting member for every step. Follow the returned part size and count rather than imposing your own split. Completing with only `upload_id` lets Brigg collect part receipts. A successful byte transfer is not a completed file: verification and scanning must finish before you receive a usable `file_id`. Retain `upload_id` for recovery. Read its state before retransferring an interrupted upload; `ready` returns the existing file ID, while an expired upload requires a new start. Temporary transfer URLs and completed file IDs have different lifetimes. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `cancelled` | boolean | Yes | Whether the unfinished upload was cancelled. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [Create upload](/developers/reference/documents/CreateUpload) - [Get upload part](/developers/reference/documents/GetUploadPart) - [Complete upload](/developers/reference/documents/CompleteUpload) - [Get upload](/developers/reference/documents/GetUpload) - [Upload and download files](/developers/files) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.CancelUpload' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "upload_id": "upl_example" }' ``` #### TypeScript ```typescript 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/documents.CancelUpload", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "upload_id": "upl_example" }), }); 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 = { "upload_id": "upl_example" } request = Request( "https://api.brigg.app/v1/operations/documents.CancelUpload", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "cancelled": true } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "upload_id": { "type": "string", "minLength": 1, "description": "Keep the upload_id and the same credential and acting member throughout the upload. Completion returns a separate file_id. [documents.CreateUpload](/developers/reference/documents/CreateUpload)." } }, "required": [ "upload_id" ], "additionalProperties": false, "examples": [ { "upload_id": "upl_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "cancelled": { "type": "boolean", "description": "Whether the unfinished upload was cancelled." } }, "required": [ "cancelled" ], "additionalProperties": false, "examples": [ { "cancelled": true } ] } ``` --- # Complete upload Verify the uploaded bytes and create one file. Send only the upload ID; Brigg collects multipart receipts automatically. The same upload always produces the same file ID. If scanning is pending, retry this call with the same idempotency key after the retry delay. Blocked files cannot be completed. POST https://api.brigg.app/v1/operations/documents.CompleteUpload ## Access & visibility Allow `documents.CompleteUpload` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `upload_id` | string | Yes | Keep the upload_id and the same credential and acting member throughout the upload. Completion returns a separate file_id. [documents.CreateUpload](/developers/reference/documents/CreateUpload). At least 1 character. | | `parts` | array of [object](#request-parts) | No | Optional receipts for uploaded parts. Completion can retrieve receipts when this list is omitted. | ### request.parts[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `part_number` | integer | Yes | One-based part number. Use 1 for a single upload; for multipart uploads, transfer every part from 1 through part_count. Greater than 0. | | `etag` | string | Yes | Optional explicit multipart receipt. When supplying parts, preserve the complete ETag value including quotes. Otherwise omit the parts array and Brigg collects the receipts automatically. At least 1 character. | ## Where this fits in an upload The [file guide](/developers/files) includes a streaming Node.js helper and the complete HTTP sequence: create an upload, request a signed URL for each part, PUT the bytes directly to that URL, then complete the upload. Never send the Brigg API key to a transfer URL. Keep the same credential and acting member for every step. Follow the returned part size and count rather than imposing your own split. Completing with only `upload_id` lets Brigg collect part receipts. A successful byte transfer is not a completed file: verification and scanning must finish before you receive a usable `file_id`. Retain `upload_id` for recovery. Read its state before retransferring an interrupted upload; `ready` returns the existing file ID, while an expired upload requires a new start. Temporary transfer URLs and completed file IDs have different lifetimes. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `file_id` | string | Yes | Stable file ID returned by documents.CompleteUpload, documents.ListDocuments or a document creation operation. Use the same ID for downloads, attachments and supported file-based workflows. Do not use a filename or storage path. | | `filename` | string | Yes | Original filename, including its extension. | | `content_type` | string or null | Yes | Media type of the file, such as application/pdf. Null when no binary file exists. | | `size_bytes` | number or null | Yes | File size in bytes. Null for a document without a downloadable binary file. | | `visibility` | string | Yes | Who may read the completed file. Personal files belong to the approved acting member; workspace files use shared access. Allowed: `"personal"`, `"workspace"`. | | `scan_status` | string or null | Yes | Malware scan state. Threats and failed scans block downloads. An unsupported file cannot be processed; only its original uploader can retrieve it as a forced download. Null is not proof of readiness. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `upload_incomplete` | Transfer all parts with their exact planned byte lengths before completing the upload. | | 409 | `file_scan_pending` | Wait Retry-After seconds, then retry with the same input and idempotency key. | | 409 | `file_scan_blocked` | The file cannot be used because its malware scan was blocked. | | 409 | `upload_closed` | This upload was cancelled or is no longer open. | | 410 | `upload_expired` | Start a new upload with a new idempotency key. | ## Next steps - [Create upload](/developers/reference/documents/CreateUpload) - [Get upload part](/developers/reference/documents/GetUploadPart) - [Get upload](/developers/reference/documents/GetUpload) - [Upload and download files](/developers/files) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.CompleteUpload' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "upload_id": "upl_example" }' ``` #### TypeScript ```typescript 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/documents.CompleteUpload", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "upload_id": "upl_example" }), }); 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 = { "upload_id": "upl_example" } request = Request( "https://api.brigg.app/v1/operations/documents.CompleteUpload", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "file_id": "f_example", "filename": "Agreement.pdf", "content_type": "application/pdf", "size_bytes": 48231, "visibility": "workspace", "scan_status": "clean" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "upload_id": { "type": "string", "minLength": 1, "description": "Keep the upload_id and the same credential and acting member throughout the upload. Completion returns a separate file_id. [documents.CreateUpload](/developers/reference/documents/CreateUpload)." }, "parts": { "type": "array", "items": { "type": "object", "properties": { "part_number": { "type": "integer", "exclusiveMinimum": 0, "description": "One-based part number. Use 1 for a single upload; for multipart uploads, transfer every part from 1 through part_count." }, "etag": { "type": "string", "minLength": 1, "description": "Optional explicit multipart receipt. When supplying parts, preserve the complete ETag value including quotes. Otherwise omit the parts array and Brigg collects the receipts automatically." } }, "required": [ "part_number", "etag" ], "additionalProperties": false }, "description": "Optional receipts for uploaded parts. Completion can retrieve receipts when this list is omitted." } }, "required": [ "upload_id" ], "additionalProperties": false, "examples": [ { "upload_id": "upl_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "file_id": { "type": "string", "description": "Stable file ID returned by documents.CompleteUpload, documents.ListDocuments or a document creation operation. Use the same ID for downloads, attachments and supported file-based workflows. Do not use a filename or storage path." }, "filename": { "type": "string", "description": "Original filename, including its extension." }, "content_type": { "type": [ "string", "null" ], "description": "Media type of the file, such as application/pdf. Null when no binary file exists." }, "size_bytes": { "type": [ "number", "null" ], "description": "File size in bytes. Null for a document without a downloadable binary file." }, "visibility": { "type": "string", "enum": [ "personal", "workspace" ], "description": "Who may read the completed file. Personal files belong to the approved acting member; workspace files use shared access." }, "scan_status": { "type": [ "string", "null" ], "description": "Malware scan state. Threats and failed scans block downloads. An unsupported file cannot be processed; only its original uploader can retrieve it as a forced download. Null is not proof of readiness." } }, "required": [ "file_id", "filename", "content_type", "size_bytes", "visibility", "scan_status" ], "additionalProperties": false, "examples": [ { "file_id": "f_example", "filename": "Agreement.pdf", "content_type": "application/pdf", "size_bytes": 48231, "visibility": "workspace", "scan_status": "clean" } ] } ``` --- # Create upload Start a file upload. Choose who may read the finished file. Workspace-only credentials create workspace files; approved member delegation can also create personal files owned by the delegated member. Obtain each transfer URL with GetUploadPart, send the bytes, then CompleteUpload. POST https://api.brigg.app/v1/operations/documents.CreateUpload ## Access & visibility Allow `documents.CreateUpload` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `filename` | string | Yes | Original filename, including its extension. At least 1 character. At most 255 characters. | | `content_type` | string | Yes | Media type of the file, such as application/pdf. Null when no binary file exists. At least 1 character. | | `size_bytes` | integer | Yes | File size in bytes. Null for a document without a downloadable binary file. Greater than 0. | | `visibility` | string | Yes | Who may read the completed file. Personal files belong to the approved acting member; workspace files use shared access. Allowed: `"personal"`, `"workspace"`. | | `path` | string | No | Folder path within the selected document collection. An empty string is its root. Default: `""`. | ## Where this fits in an upload The [file guide](/developers/files) includes a streaming Node.js helper and the complete HTTP sequence: create an upload, request a signed URL for each part, PUT the bytes directly to that URL, then complete the upload. Never send the Brigg API key to a transfer URL. Keep the same credential and acting member for every step. Follow the returned part size and count rather than imposing your own split. Completing with only `upload_id` lets Brigg collect part receipts. A successful byte transfer is not a completed file: verification and scanning must finish before you receive a usable `file_id`. Retain `upload_id` for recovery. Read its state before retransferring an interrupted upload; `ready` returns the existing file ID, while an expired upload requires a new start. Temporary transfer URLs and completed file IDs have different lifetimes. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `upload_id` | string | Yes | Upload ID returned by documents.CreateUpload. Only the credential that created this upload can transfer parts, complete it or cancel it. This is different from the completed file ID. | | `state` | string | Yes | Upload lifecycle state. Uploading bytes and completing the file are separate steps. Allowed: `"uploading"`, `"ready"`, `"cancelled"`, `"expired"`. | | `expires_at` | number | Yes | Upload expiry, in Unix milliseconds. Complete the upload before this time. | | `mode` | string | Yes | Transfer mode selected by Brigg: single upload or multipart upload. Follow the returned part count and part size. Allowed: `"single"`, `"multipart"`. | | `part_size` | integer | Yes | Bytes in each part, except the last part which contains the remaining bytes. Split the original file at these boundaries. | | `part_count` | integer | Yes | Number of parts to transfer before completion. One means the entire file is sent in a single PUT request. | | `file_id` | string | No | Stable file ID returned by documents.CompleteUpload, documents.ListDocuments or a document creation operation. Use the same ID for downloads, attachments and supported file-based workflows. Do not use a filename or storage path. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [Get upload part](/developers/reference/documents/GetUploadPart) - [Complete upload](/developers/reference/documents/CompleteUpload) - [Get upload](/developers/reference/documents/GetUpload) - [Upload and download files](/developers/files) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.CreateUpload' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "filename": "Agreement.pdf", "content_type": "application/pdf", "size_bytes": 48231, "visibility": "workspace" }' ``` #### TypeScript ```typescript 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/documents.CreateUpload", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "filename": "Agreement.pdf", "content_type": "application/pdf", "size_bytes": 48231, "visibility": "workspace" }), }); 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 = { "filename": "Agreement.pdf", "content_type": "application/pdf", "size_bytes": 48231, "visibility": "workspace" } request = Request( "https://api.brigg.app/v1/operations/documents.CreateUpload", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "upload_id": "upl_example", "state": "uploading", "expires_at": 1794387600000, "mode": "single", "part_size": 48231, "part_count": 1 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "filename": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Original filename, including its extension." }, "content_type": { "type": "string", "minLength": 1, "description": "Media type of the file, such as application/pdf. Null when no binary file exists." }, "size_bytes": { "type": "integer", "exclusiveMinimum": 0, "description": "File size in bytes. Null for a document without a downloadable binary file." }, "visibility": { "type": "string", "enum": [ "personal", "workspace" ], "description": "Who may read the completed file. Personal files belong to the approved acting member; workspace files use shared access." }, "path": { "type": "string", "default": "", "description": "Folder path within the selected document collection. An empty string is its root." } }, "required": [ "filename", "content_type", "size_bytes", "visibility" ], "additionalProperties": false, "examples": [ { "filename": "Agreement.pdf", "content_type": "application/pdf", "size_bytes": 48231, "visibility": "workspace" } ] } ``` ```json-schema-response { "type": "object", "properties": { "upload_id": { "type": "string", "description": "Upload ID returned by documents.CreateUpload. Only the credential that created this upload can transfer parts, complete it or cancel it. This is different from the completed file ID." }, "state": { "type": "string", "enum": [ "uploading", "ready", "cancelled", "expired" ], "description": "Upload lifecycle state. Uploading bytes and completing the file are separate steps." }, "expires_at": { "type": "number", "description": "Upload expiry, in Unix milliseconds. Complete the upload before this time." }, "mode": { "type": "string", "enum": [ "single", "multipart" ], "description": "Transfer mode selected by Brigg: single upload or multipart upload. Follow the returned part count and part size." }, "part_size": { "type": "integer", "description": "Bytes in each part, except the last part which contains the remaining bytes. Split the original file at these boundaries." }, "part_count": { "type": "integer", "description": "Number of parts to transfer before completion. One means the entire file is sent in a single PUT request." }, "file_id": { "type": "string", "description": "Stable file ID returned by documents.CompleteUpload, documents.ListDocuments or a document creation operation. Use the same ID for downloads, attachments and supported file-based workflows. Do not use a filename or storage path." } }, "required": [ "upload_id", "state", "expires_at", "mode", "part_size", "part_count" ], "additionalProperties": false, "examples": [ { "upload_id": "upl_example", "state": "uploading", "expires_at": 1794387600000, "mode": "single", "part_size": 48231, "part_count": 1 } ] } ``` --- # Create folder Create a folder in a document tree. POST https://api.brigg.app/v1/operations/documents.CreateFolder ## Access & visibility Allow `documents.CreateFolder` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `scope` | string | Yes | Collection: org is workspace-shared, user belongs to the approved acting member, and resources contains shared, predefined resource roots. Use ListDocuments with the same scope to discover existing paths. Allowed: `"org"`, `"user"`, `"resources"`. | | `path` | string | Yes | Nonempty path within the selected collection, such as Projects/Archive. Use slash-separated names, not a file ID or a URL. Leading/trailing and repeated slashes are normalized; dot segments are refused. Use the returned/listed path for later calls. At least 1 character. At most 1024 characters. | ## Response Returns **200 OK** with a JSON body. Discover resource roots with ListDocuments with scope=resources at the root. You may create subfolders beneath them, but cannot create or replace the predefined roots. This changes folder structure only and does not move documents. | Field | Type | Required | Description | | --- | --- | --- | --- | | `path` | string | Yes | Canonical folder path. Parent folders are created as needed; creating an existing folder leaves it in place. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List documents](/developers/reference/documents/ListDocuments) - [Move document](/developers/reference/documents/MoveDocument) - [Delete folder](/developers/reference/documents/DeleteFolder) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Create a nested folder The returned path is the value to retain for listing and placement. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.CreateFolder' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "scope": "org", "path": "Projects/Archive" }' ``` #### TypeScript ```typescript 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/documents.CreateFolder", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "scope": "org", "path": "Projects/Archive" }), }); 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 = { "scope": "org", "path": "Projects/Archive" } request = Request( "https://api.brigg.app/v1/operations/documents.CreateFolder", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "path": "Projects/Archive" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "scope": { "type": "string", "enum": [ "org", "user", "resources" ], "description": "Collection: org is workspace-shared, user belongs to the approved acting member, and resources contains shared, predefined resource roots. Use ListDocuments with the same scope to discover existing paths." }, "path": { "type": "string", "minLength": 1, "maxLength": 1024, "description": "Nonempty path within the selected collection, such as Projects/Archive. Use slash-separated names, not a file ID or a URL. Leading/trailing and repeated slashes are normalized; dot segments are refused. Use the returned/listed path for later calls." } }, "required": [ "scope", "path" ], "additionalProperties": false, "examples": [ { "scope": "org", "path": "Projects/Archive" } ] } ``` ```json-schema-response { "type": "object", "properties": { "path": { "type": "string", "description": "Canonical folder path. Parent folders are created as needed; creating an existing folder leaves it in place." } }, "required": [ "path" ], "additionalProperties": false, "examples": [ { "path": "Projects/Archive" } ] } ``` --- # Delete folder Delete an empty document folder. Folders containing documents or child folders, and system-managed roots, cannot be deleted. POST https://api.brigg.app/v1/operations/documents.DeleteFolder ## Access & visibility Allow `documents.DeleteFolder` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `scope` | string | Yes | Collection: org is workspace-shared, user belongs to the approved acting member, and resources contains shared, predefined resource roots. Use ListDocuments with the same scope to discover existing paths. Allowed: `"org"`, `"user"`, `"resources"`. | | `path` | string | Yes | Nonempty path within the selected collection, such as Projects/Archive. Use slash-separated names, not a file ID or a URL. Leading/trailing and repeated slashes are normalized; dot segments are refused. Use the returned/listed path for later calls. At least 1 character. At most 1024 characters. | ## Remove the folder, not its contents Use [List documents](/developers/reference/documents/ListDocuments) with the same scope and path first. Both items and folders must be empty. Move documents elsewhere and remove child folders deliberately; this operation never recursively deletes their content. The collection root, predefined resources roots and workspace roots reserved by an installed app cannot be deleted. A missing empty folder succeeds. The path is a location within the collection, not a file ID. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | True when the selected folder is absent after the call. An already absent empty folder also succeeds. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 400 | `not_empty` | The folder contains documents or child folders. List its contents and move or remove them deliberately before deleting the folder. | | 400 | `reserved_root` | An installed app owns this workspace root. Its contents can be edited, but the root cannot be deleted. | ## Next steps - [List documents](/developers/reference/documents/ListDocuments) - [Move document](/developers/reference/documents/MoveDocument) - [Create folder](/developers/reference/documents/CreateFolder) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Remove an empty archive folder Inspect the exact folder before removing it. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.DeleteFolder' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "scope": "org", "path": "Projects/Archive" }' ``` #### TypeScript ```typescript 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/documents.DeleteFolder", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "scope": "org", "path": "Projects/Archive" }), }); 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 = { "scope": "org", "path": "Projects/Archive" } request = Request( "https://api.brigg.app/v1/operations/documents.DeleteFolder", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "scope": { "type": "string", "enum": [ "org", "user", "resources" ], "description": "Collection: org is workspace-shared, user belongs to the approved acting member, and resources contains shared, predefined resource roots. Use ListDocuments with the same scope to discover existing paths." }, "path": { "type": "string", "minLength": 1, "maxLength": 1024, "description": "Nonempty path within the selected collection, such as Projects/Archive. Use slash-separated names, not a file ID or a URL. Leading/trailing and repeated slashes are normalized; dot segments are refused. Use the returned/listed path for later calls." } }, "required": [ "scope", "path" ], "additionalProperties": false, "examples": [ { "scope": "org", "path": "Projects/Archive" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "True when the selected folder is absent after the call. An already absent empty folder also succeeds." } }, "required": [ "ok" ], "additionalProperties": false, "examples": [ { "ok": true } ] } ``` --- # Get bundle sharing Inspect content visibility, public-web publication and active share-link metadata without creating or revealing bearer share links. POST https://api.brigg.app/v1/operations/documents.GetBundleSharing ## Access & visibility Allow `documents.GetBundleSharing` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `content_id` | string | Yes | Content identity from ListBundles. For generated documents this is the document_id used by ShareDocument; it is not an uploaded or collaborative text file_id. At least 1 character. | ## Interpret base access and outward sharing Find content_id with [List bundles](/developers/reference/workspace/ListBundles). Workspace content can be inspected by a member with access; private content requires its owner or an authorized workspace manager. The key still needs approved member delegation. base describes access inside Brigg. audience also considers active links and public-web publication. A private base with audience=link is possible: the owner's private content has been shared with link holders. This operation changes none of those settings. For generated documents, use [Share document](/developers/reference/documents/ShareDocument) to create a link and retain its URL, or [Revoke document share](/developers/reference/documents/RevokeDocumentShare) with links[].share_id to withdraw one. Metadata does not reveal existing bearer URLs. Uploaded files and collaborative text documents use their separate file and text-sharing operations. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `content_id` | string | Yes | Opaque ID from workspace.ListBundles. Its kind distinguishes apps, websites, newsletters, documents, templates and integrations; it is not an uploaded file ID. | | `label` | string | Yes | Human-readable name for this content or saved version. | | `audience` | string | Yes | Widest active audience: private, workspace, link or web. Web takes precedence over link; when neither exists this equals base. | | `base` | string | Yes | Underlying access inside Brigg: private or workspace. Share links and public-web publication add audiences without changing this base. This is not a version ID. | | `web` | boolean | Yes | True only when deliberately published on the public web. Saving or sharing with the workspace alone does not set this flag. | | `public_url` | string or null | Yes | Public website URL when web=true; otherwise null. This is distinct from a private bearer share link. | | `links` | array of [object](#response-links) | Yes | Active, unexpired share-link metadata. No usable bearer URLs or tokens are returned; keep a new link's URL when ShareDocument creates it. | ### response.links[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `share_id` | string | Yes | Non-secret management ID. Pass it with this content's document_id to RevokeDocumentShare; it cannot open the content. | | `created_at` | number | Yes | Creation timestamp in Unix milliseconds. | | `created_by` | string | Yes | Account ID responsible for creating this item. | | `expires_at` | number or null | Yes | Expiry in Unix milliseconds, or null when no expiry is recorded. | | `version_id` | string | Yes | Saved content version fixed by this link. Later edits do not change what this link shares. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | The acting member must be allowed to act on this content. Private content requires its owner or an authorized workspace manager; the key's delegation grant still applies. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [List bundles](/developers/reference/workspace/ListBundles) - [Share document](/developers/reference/documents/ShareDocument) - [Revoke document share](/developers/reference/documents/RevokeDocumentShare) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Workspace content without outward links No web publication or active bearer links. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.GetBundleSharing' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Brigg-Act-As: $BRIGG_ACT_AS" \ --data-raw '{ "content_id": "c_proposal" }' ``` #### 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 response = await fetch("https://api.brigg.app/v1/operations/documents.GetBundleSharing", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Brigg-Act-As": actAs, }, body: JSON.stringify({ "content_id": "c_proposal" }), }); 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 payload = { "content_id": "c_proposal" } request = Request( "https://api.brigg.app/v1/operations/documents.GetBundleSharing", 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"], }, 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 { "content_id": "c_proposal", "label": "Consulting proposal", "audience": "workspace", "base": "workspace", "web": false, "public_url": null, "links": [] } ``` ### Private content with a live share link The link adds access for its holders without changing the private base. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.GetBundleSharing' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Brigg-Act-As: $BRIGG_ACT_AS" \ --data-raw '{ "content_id": "c_proposal" }' ``` #### 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 response = await fetch("https://api.brigg.app/v1/operations/documents.GetBundleSharing", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Brigg-Act-As": actAs, }, body: JSON.stringify({ "content_id": "c_proposal" }), }); 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 payload = { "content_id": "c_proposal" } request = Request( "https://api.brigg.app/v1/operations/documents.GetBundleSharing", 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"], }, 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 { "content_id": "c_proposal", "label": "Consulting proposal", "audience": "link", "base": "private", "web": false, "public_url": null, "links": [ { "share_id": "share_proposal", "created_at": 1794301200000, "created_by": "a_alex", "expires_at": 1794906000000, "version_id": "v_proposal_3" } ] } ``` ### Published on the web The public URL is present only while web publication is active. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.GetBundleSharing' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Brigg-Act-As: $BRIGG_ACT_AS" \ --data-raw '{ "content_id": "c_proposal" }' ``` #### 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 response = await fetch("https://api.brigg.app/v1/operations/documents.GetBundleSharing", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Brigg-Act-As": actAs, }, body: JSON.stringify({ "content_id": "c_proposal" }), }); 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 payload = { "content_id": "c_proposal" } request = Request( "https://api.brigg.app/v1/operations/documents.GetBundleSharing", 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"], }, 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 { "content_id": "c_proposal", "label": "Consulting proposal", "audience": "web", "base": "workspace", "web": true, "public_url": "https://example.com/proposal", "links": [] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "content_id": { "type": "string", "minLength": 1, "description": "Content identity from ListBundles. For generated documents this is the document_id used by ShareDocument; it is not an uploaded or collaborative text file_id." } }, "required": [ "content_id" ], "additionalProperties": false, "examples": [ { "content_id": "c_proposal" } ] } ``` ```json-schema-response { "type": "object", "properties": { "content_id": { "type": "string", "description": "Opaque ID from workspace.ListBundles. Its kind distinguishes apps, websites, newsletters, documents, templates and integrations; it is not an uploaded file ID." }, "label": { "type": "string", "description": "Human-readable name for this content or saved version." }, "audience": { "type": "string", "description": "Widest active audience: private, workspace, link or web. Web takes precedence over link; when neither exists this equals base." }, "base": { "type": "string", "description": "Underlying access inside Brigg: private or workspace. Share links and public-web publication add audiences without changing this base. This is not a version ID." }, "web": { "type": "boolean", "description": "True only when deliberately published on the public web. Saving or sharing with the workspace alone does not set this flag." }, "public_url": { "type": [ "string", "null" ], "description": "Public website URL when web=true; otherwise null. This is distinct from a private bearer share link." }, "links": { "type": "array", "items": { "type": "object", "properties": { "share_id": { "type": "string", "description": "Non-secret management ID. Pass it with this content's document_id to RevokeDocumentShare; it cannot open the content." }, "created_at": { "type": "number", "description": "Creation timestamp in Unix milliseconds." }, "created_by": { "type": "string", "description": "Account ID responsible for creating this item." }, "expires_at": { "type": [ "number", "null" ], "description": "Expiry in Unix milliseconds, or null when no expiry is recorded." }, "version_id": { "type": "string", "description": "Saved content version fixed by this link. Later edits do not change what this link shares." } }, "required": [ "share_id", "created_at", "created_by", "expires_at", "version_id" ], "additionalProperties": false }, "description": "Active, unexpired share-link metadata. No usable bearer URLs or tokens are returned; keep a new link's URL when ShareDocument creates it." } }, "required": [ "content_id", "label", "audience", "base", "web", "public_url", "links" ], "additionalProperties": false, "examples": [ { "content_id": "c_proposal", "label": "Consulting proposal", "audience": "workspace", "base": "workspace", "web": false, "public_url": null, "links": [] } ] } ``` --- # Revoke document share Revoke one saved-document link by share_id. The link stops granting access; other links and the document’s normal permissions are unchanged. POST https://api.brigg.app/v1/operations/documents.RevokeDocumentShare ## Access & visibility Allow `documents.RevokeDocumentShare` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `document_id` | string | Yes | Document ID from workspace.ListBundles filtered to kind=document. This is different from the file_id of an uploaded or text document. At least 1 character. | | `share_id` | string | Yes | Non-secret identifier of a share link returned by a share or share-list operation. Use it to revoke that link; it cannot be used to open the document. Treat the separate url value as a bearer credential. At least 1 character. | ## A share link grants access The returned `url` is a bearer link: someone holding it can open the shared content within that link's terms. Keep it out of application logs and analytics. The separate `share_id` identifies a link for management and revocation; it is not sufficient to read content. Sharing a text document uses `file_id`; sharing a generated document uses `document_id` and can name a `version_id`. Do not substitute one ID type for another. Revoking one share link does not remove other links or change the content's underlying workspace/private visibility. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `revoked` | boolean | Yes | Whether the share link has been revoked. | | `version_id` | string or null | Yes | The version the link pointed at, or null when there was none. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | ## Next steps - [List text document shares](/developers/reference/documents/ListTextDocumentShares) - [Revoke text document share](/developers/reference/documents/RevokeTextDocumentShare) - [Get bundle sharing](/developers/reference/documents/GetBundleSharing) - [Upload and download files](/developers/files) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.RevokeDocumentShare' \ -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 '{ "document_id": "e_example", "share_id": "e_example" }' ``` #### 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/documents.RevokeDocumentShare", { 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({ "document_id": "e_example", "share_id": "e_example" }), }); 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 = { "document_id": "e_example", "share_id": "e_example" } request = Request( "https://api.brigg.app/v1/operations/documents.RevokeDocumentShare", 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 { "revoked": false, "version_id": null } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "document_id": { "type": "string", "minLength": 1, "description": "Document ID from workspace.ListBundles filtered to kind=document. This is different from the file_id of an uploaded or text document." }, "share_id": { "type": "string", "minLength": 1, "description": "Non-secret identifier of a share link returned by a share or share-list operation. Use it to revoke that link; it cannot be used to open the document. Treat the separate url value as a bearer credential." } }, "required": [ "document_id", "share_id" ], "additionalProperties": false, "examples": [ { "document_id": "e_example", "share_id": "e_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "revoked": { "type": "boolean", "description": "Whether the share link has been revoked." }, "version_id": { "type": [ "string", "null" ], "description": "The version the link pointed at, or null when there was none." } }, "required": [ "revoked", "version_id" ], "additionalProperties": false, "examples": [ { "revoked": false, "version_id": null } ] } ``` --- # Share document Create an expiring read-only link to a saved document version. Anyone holding the returned URL can read that version until expiry or revocation. Keep the share_id for management; it grants no access by itself. POST https://api.brigg.app/v1/operations/documents.ShareDocument ## Access & visibility Allow `documents.ShareDocument` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `document_id` | string | Yes | Document ID from workspace.ListBundles filtered to kind=document. This is different from the file_id of an uploaded or text document. At least 1 character. | | `version_id` | string | No | Version identifier. At least 1 character. | | `ttl_days` | integer | No | Number of days before the share link expires. Maximum: 365. Greater than 0. | ## A share link grants access The returned `url` is a bearer link: someone holding it can open the shared content within that link's terms. Keep it out of application logs and analytics. The separate `share_id` identifies a link for management and revocation; it is not sufficient to read content. Sharing a text document uses `file_id`; sharing a generated document uses `document_id` and can name a `version_id`. Do not substitute one ID type for another. Revoking one share link does not remove other links or change the content's underlying workspace/private visibility. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `document_id` | string | Yes | Document ID from workspace.ListBundles filtered to kind=document. This is different from the file_id of an uploaded or text document. | | `url` | string | Yes | Absolute URL, including its scheme. | | `share_id` | string | Yes | Non-secret identifier of a share link returned by a share or share-list operation. Use it to revoke that link; it cannot be used to open the document. Treat the separate url value as a bearer credential. | | `version_id` | string | Yes | Version identifier. | | `expires_at` | number | Yes | Expiry time in Unix milliseconds. Obtain a fresh transfer or download URL after expiry. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | ## Next steps - [List text document shares](/developers/reference/documents/ListTextDocumentShares) - [Revoke text document share](/developers/reference/documents/RevokeTextDocumentShare) - [Get bundle sharing](/developers/reference/documents/GetBundleSharing) - [Upload and download files](/developers/files) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.ShareDocument' \ -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 '{ "document_id": "e_example" }' ``` #### 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/documents.ShareDocument", { 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({ "document_id": "e_example" }), }); 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 = { "document_id": "e_example" } request = Request( "https://api.brigg.app/v1/operations/documents.ShareDocument", 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 { "document_id": "e_example", "url": "https://example.com", "share_id": "e_example", "version_id": "e_example", "expires_at": 1794301200000 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "document_id": { "type": "string", "minLength": 1, "description": "Document ID from workspace.ListBundles filtered to kind=document. This is different from the file_id of an uploaded or text document." }, "version_id": { "type": "string", "minLength": 1, "description": "Version identifier." }, "ttl_days": { "type": "integer", "exclusiveMinimum": 0, "maximum": 365, "description": "Number of days before the share link expires." } }, "required": [ "document_id" ], "additionalProperties": false, "examples": [ { "document_id": "e_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "document_id": { "type": "string", "description": "Document ID from workspace.ListBundles filtered to kind=document. This is different from the file_id of an uploaded or text document." }, "url": { "type": "string", "description": "Absolute URL, including its scheme." }, "share_id": { "type": "string", "description": "Non-secret identifier of a share link returned by a share or share-list operation. Use it to revoke that link; it cannot be used to open the document. Treat the separate url value as a bearer credential." }, "version_id": { "type": "string", "description": "Version identifier." }, "expires_at": { "type": "number", "description": "Expiry time in Unix milliseconds. Obtain a fresh transfer or download URL after expiry." } }, "required": [ "document_id", "url", "share_id", "version_id", "expires_at" ], "additionalProperties": false, "examples": [ { "document_id": "e_example", "url": "https://example.com", "share_id": "e_example", "version_id": "e_example", "expires_at": 1794301200000 } ] } ``` --- # Get text document content Read a text document's last stored Markdown and filename. For current collaborative content, use ReadTextDocument. POST https://api.brigg.app/v1/operations/documents.GetTextDocumentContent ## Access & visibility Allow `documents.GetTextDocumentContent` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `file_id` | string | Yes | Use the file_id of a collaborative text document. Find an existing document with [ListDocuments](/developers/reference/documents/ListDocuments) and select kind=text_document. An uploaded PDF, Word file or plain-text file is not a collaborative text document. [documents.CreateTextDocument](/developers/reference/documents/CreateTextDocument). At least 1 character. | ## Work with text and saved versions All documents use a stable `file_id`. Select `document_kind=text_document` from the listing for these collaborative text operations. [Read text document](/developers/reference/documents/ReadTextDocument) returns its current Markdown and location. For an exact change, use [Edit text document](/developers/reference/documents/EditTextDocument) with the existing text and its replacement; this avoids sending an old full copy over another edit. [Replace text document](/developers/reference/documents/ReplaceTextDocument) replaces the entire Markdown body. Send the read response’s `revision` as `expected_revision` to refuse intervening changes atomically. Re-read before resolving a failed match or revision conflict. A saved `version_id` identifies historical content. List versions before reading or reverting one, and use [Checkpoint text document](/developers/reference/documents/CheckpointTextDocument) when you need a named saved point. A revert changes current content; it is not just a historical read. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `md` | string | Yes | Last stored Markdown projection. This can lag behind the live editor; use ReadTextDocument for a current read before editing. | | `filename` | string | Yes | Current document name. A collaborative text document is not an uploaded PDF or Word file and does not require a filename extension. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | | 409 | `not_text_document` | This file is not a collaborative text document. Use CreateTextDocument or select kind=text_document from ListDocuments. | ## Next steps - [Read text document](/developers/reference/documents/ReadTextDocument) - [Create text document](/developers/reference/documents/CreateTextDocument) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Read stored Markdown For current live text use ReadTextDocument instead. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.GetTextDocumentContent' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "file_id": "f_project_notes" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/documents.GetTextDocumentContent", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "file_id": "f_project_notes" }), }); 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 payload = { "file_id": "f_project_notes" } request = Request( "https://api.brigg.app/v1/operations/documents.GetTextDocumentContent", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "md": "# Project notes\n\nThe kickoff is on Tuesday.", "filename": "Project notes" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "file_id": { "type": "string", "minLength": 1, "description": "Use the file_id of a collaborative text document. Find an existing document with [ListDocuments](/developers/reference/documents/ListDocuments) and select kind=text_document. An uploaded PDF, Word file or plain-text file is not a collaborative text document. [documents.CreateTextDocument](/developers/reference/documents/CreateTextDocument)." } }, "required": [ "file_id" ], "additionalProperties": false, "examples": [ { "file_id": "f_project_notes" } ] } ``` ```json-schema-response { "type": "object", "properties": { "md": { "type": "string", "description": "Last stored Markdown projection. This can lag behind the live editor; use ReadTextDocument for a current read before editing." }, "filename": { "type": "string", "description": "Current document name. A collaborative text document is not an uploaded PDF or Word file and does not require a filename extension." } }, "required": [ "md", "filename" ], "additionalProperties": false, "examples": [ { "md": "# Project notes\n\nThe kickoff is on Tuesday.", "filename": "Project notes" } ] } ``` --- # Get text document version Read a saved version of a text document, including its Markdown, author and creation time. Images use authenticated document URLs. POST https://api.brigg.app/v1/operations/documents.GetTextDocumentVersion ## Access & visibility Allow `documents.GetTextDocumentVersion` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `file_id` | string | Yes | Use the file_id of a collaborative text document. Find an existing document with [ListDocuments](/developers/reference/documents/ListDocuments) and select kind=text_document. An uploaded PDF, Word file or plain-text file is not a collaborative text document. [documents.CreateTextDocument](/developers/reference/documents/CreateTextDocument). At least 1 character. | | `version_id` | string | Yes | Saved version_id from ListTextDocumentVersions for this same file_id. It is not a different document's ID. At least 1 character. | ## Work with text and saved versions All documents use a stable `file_id`. Select `document_kind=text_document` from the listing for these collaborative text operations. [Read text document](/developers/reference/documents/ReadTextDocument) returns its current Markdown and location. For an exact change, use [Edit text document](/developers/reference/documents/EditTextDocument) with the existing text and its replacement; this avoids sending an old full copy over another edit. [Replace text document](/developers/reference/documents/ReplaceTextDocument) replaces the entire Markdown body. Send the read response’s `revision` as `expected_revision` to refuse intervening changes atomically. Re-read before resolving a failed match or revision conflict. A saved `version_id` identifies historical content. List versions before reading or reverting one, and use [Checkpoint text document](/developers/reference/documents/CheckpointTextDocument) when you need a named saved point. A revert changes current content; it is not just a historical read. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `version_id` | string | Yes | Saved version identity. Keep it together with the document's file_id to read or restore this version. | | `md` | string | Yes | Document content formatted as Markdown. | | `kind` | string | Yes | How the version was saved: named is a user-labelled checkpoint; auto is an automatic checkpoint, and pre_revert preserves the state before a restore. | | `label` | string or null | Yes | Name supplied for a named checkpoint, or null when no label was recorded. | | `created_by` | string or null | Yes | Account that created the record, or null when no account is recorded. | | `created_at` | number | Yes | Creation time in Unix milliseconds. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | | 409 | `not_text_document` | This file is not a collaborative text document. Use CreateTextDocument or select kind=text_document from ListDocuments. | ## Next steps - [List text document versions](/developers/reference/documents/ListTextDocumentVersions) - [Read text document](/developers/reference/documents/ReadTextDocument) - [Revert text document](/developers/reference/documents/RevertTextDocument) - [Create text document](/developers/reference/documents/CreateTextDocument) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Read a saved version Reading history does not change the current document. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.GetTextDocumentVersion' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "file_id": "f_project_notes", "version_id": "tdv_project_notes_2" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/documents.GetTextDocumentVersion", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "file_id": "f_project_notes", "version_id": "tdv_project_notes_2" }), }); 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 payload = { "file_id": "f_project_notes", "version_id": "tdv_project_notes_2" } request = Request( "https://api.brigg.app/v1/operations/documents.GetTextDocumentVersion", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "version_id": "tdv_project_notes_2", "md": "# Project notes\n\nThe kickoff is on Tuesday.", "kind": "named", "label": "Before legal review", "created_by": "a_jamie", "created_at": 1794301200000 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "file_id": { "type": "string", "minLength": 1, "description": "Use the file_id of a collaborative text document. Find an existing document with [ListDocuments](/developers/reference/documents/ListDocuments) and select kind=text_document. An uploaded PDF, Word file or plain-text file is not a collaborative text document. [documents.CreateTextDocument](/developers/reference/documents/CreateTextDocument)." }, "version_id": { "type": "string", "minLength": 1, "description": "Saved version_id from ListTextDocumentVersions for this same file_id. It is not a different document's ID." } }, "required": [ "file_id", "version_id" ], "additionalProperties": false, "examples": [ { "file_id": "f_project_notes", "version_id": "tdv_project_notes_2" } ] } ``` ```json-schema-response { "type": "object", "properties": { "version_id": { "type": "string", "description": "Saved version identity. Keep it together with the document's file_id to read or restore this version." }, "md": { "type": "string", "description": "Document content formatted as Markdown." }, "kind": { "type": "string", "description": "How the version was saved: named is a user-labelled checkpoint; auto is an automatic checkpoint, and pre_revert preserves the state before a restore." }, "label": { "type": [ "string", "null" ], "description": "Name supplied for a named checkpoint, or null when no label was recorded." }, "created_by": { "type": [ "string", "null" ], "description": "Account that created the record, or null when no account is recorded." }, "created_at": { "type": "number", "description": "Creation time in Unix milliseconds." } }, "required": [ "version_id", "md", "kind", "label", "created_by", "created_at" ], "additionalProperties": false, "examples": [ { "version_id": "tdv_project_notes_2", "md": "# Project notes\n\nThe kickoff is on Tuesday.", "kind": "named", "label": "Before legal review", "created_by": "a_jamie", "created_at": 1794301200000 } ] } ``` --- # List text document shares List active, unexpired share links for a text document you can access, including expiry and access counts. Treat each returned URL as a bearer credential. Use share_id to revoke an individual link. POST https://api.brigg.app/v1/operations/documents.ListTextDocumentShares ## Access & visibility Allow `documents.ListTextDocumentShares` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `file_id` | string | Yes | Use the file_id of a collaborative text document. Find an existing document with [ListDocuments](/developers/reference/documents/ListDocuments) and select kind=text_document. An uploaded PDF, Word file or plain-text file is not a collaborative text document. [documents.CreateTextDocument](/developers/reference/documents/CreateTextDocument). At least 1 character. | ## A share link grants access The returned `url` is a bearer link: someone holding it can open the shared content within that link's terms. Keep it out of application logs and analytics. The separate `share_id` identifies a link for management and revocation; it is not sufficient to read content. Sharing a text document uses `file_id`; sharing a generated document uses `document_id` and can name a `version_id`. Do not substitute one ID type for another. Revoking one share link does not remove other links or change the content's underlying workspace/private visibility. ## Response Returns **200 OK** with a JSON body. This operation has no continuation cursor. An empty `items` array means no matching visible results were returned. An empty items array means no active links remain. Each URL still grants access to the current content; this response contains bearer links and should not be logged. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [Document share link](#document-share-link-response-items) | Yes | Active, unexpired share links for this text document, newest first. Revoked and expired links are excluded. This operation has no cursor pagination. | ### Document share link · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `share_id` | string | Yes | Non-secret identifier of a share link returned by a share or share-list operation. Use it to revoke that link; it cannot be used to open the document. Treat the separate url value as a bearer credential. | | `url` | string | Yes | Bearer link that grants access to this document. Treat it as a secret and share it only with intended readers. | | `created_by` | string or null | Yes | Account ID of the person who created this link. | | `created_at` | number | Yes | Share-link creation time in Unix milliseconds. | | `expires_at` | number | Yes | Expiry time in Unix milliseconds. Access through this link stops after this time. | | `access_count` | number | Yes | Number of recorded accesses through this share link. | | `last_accessed_at` | number or null | Yes | Most recent access time in Unix milliseconds, or null if the link has not been used. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 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. | | 409 | `not_text_document` | This file is not a collaborative text document. Use CreateTextDocument or select kind=text_document from ListDocuments. | ## Next steps - [Share text document](/developers/reference/documents/ShareTextDocument) - [Revoke text document share](/developers/reference/documents/RevokeTextDocumentShare) - [Read text document](/developers/reference/documents/ReadTextDocument) - [Create text document](/developers/reference/documents/CreateTextDocument) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### List active links This link has been opened twice; counters describe accesses, not unique people. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.ListTextDocumentShares' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Brigg-Act-As: $BRIGG_ACT_AS" \ --data-raw '{ "file_id": "f_project_notes" }' ``` #### 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 response = await fetch("https://api.brigg.app/v1/operations/documents.ListTextDocumentShares", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Brigg-Act-As": actAs, }, body: JSON.stringify({ "file_id": "f_project_notes" }), }); 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 payload = { "file_id": "f_project_notes" } request = Request( "https://api.brigg.app/v1/operations/documents.ListTextDocumentShares", 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"], }, 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 { "items": [ { "share_id": "share_project_notes", "url": "https://app.example.com/share/fictional-link?org=o_northstar", "expires_at": 1794906000000, "created_by": "a_jamie", "created_at": 1794301200000, "access_count": 2, "last_accessed_at": 1794387600000 } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "file_id": { "type": "string", "minLength": 1, "description": "Use the file_id of a collaborative text document. Find an existing document with [ListDocuments](/developers/reference/documents/ListDocuments) and select kind=text_document. An uploaded PDF, Word file or plain-text file is not a collaborative text document. [documents.CreateTextDocument](/developers/reference/documents/CreateTextDocument)." } }, "required": [ "file_id" ], "additionalProperties": false, "examples": [ { "file_id": "f_project_notes" } ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "share_id": { "type": "string", "description": "Non-secret identifier of a share link returned by a share or share-list operation. Use it to revoke that link; it cannot be used to open the document. Treat the separate url value as a bearer credential.", "examples": [ "share_proposal" ] }, "url": { "type": "string", "description": "Bearer link that grants access to this document. Treat it as a secret and share it only with intended readers.", "examples": [ "https://example.com/share/proposal" ] }, "created_by": { "type": [ "string", "null" ], "description": "Account ID of the person who created this link.", "examples": [ "account_alex" ] }, "created_at": { "type": "number", "description": "Share-link creation time in Unix milliseconds." }, "expires_at": { "type": "number", "description": "Expiry time in Unix milliseconds. Access through this link stops after this time.", "examples": [ 1794906000000 ] }, "access_count": { "type": "number", "description": "Number of recorded accesses through this share link.", "examples": [ 0 ] }, "last_accessed_at": { "type": [ "number", "null" ], "description": "Most recent access time in Unix milliseconds, or null if the link has not been used.", "examples": [ null ] } }, "required": [ "share_id", "url", "created_by", "created_at", "expires_at", "access_count", "last_accessed_at" ], "additionalProperties": false, "title": "Document share link" }, "description": "Active, unexpired share links for this text document, newest first. Revoked and expired links are excluded. This operation has no cursor pagination." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "share_id": "share_project_notes", "url": "https://app.example.com/share/fictional-link?org=o_northstar", "expires_at": 1794906000000, "created_by": "a_jamie", "created_at": 1794301200000, "access_count": 2, "last_accessed_at": 1794387600000 } ] } ] } ``` --- # List text document versions Read a text document's version history, newest first. Includes version IDs, labels, word counts, contributors and timestamps. POST https://api.brigg.app/v1/operations/documents.ListTextDocumentVersions ## Access & visibility Allow `documents.ListTextDocumentVersions` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `file_id` | string | Yes | Use the file_id of a collaborative text document. Find an existing document with [ListDocuments](/developers/reference/documents/ListDocuments) and select kind=text_document. An uploaded PDF, Word file or plain-text file is not a collaborative text document. [documents.CreateTextDocument](/developers/reference/documents/CreateTextDocument). At least 1 character. | ## Work with text and saved versions All documents use a stable `file_id`. Select `document_kind=text_document` from the listing for these collaborative text operations. [Read text document](/developers/reference/documents/ReadTextDocument) returns its current Markdown and location. For an exact change, use [Edit text document](/developers/reference/documents/EditTextDocument) with the existing text and its replacement; this avoids sending an old full copy over another edit. [Replace text document](/developers/reference/documents/ReplaceTextDocument) replaces the entire Markdown body. Send the read response’s `revision` as `expected_revision` to refuse intervening changes atomically. Re-read before resolving a failed match or revision conflict. A saved `version_id` identifies historical content. List versions before reading or reverting one, and use [Checkpoint text document](/developers/reference/documents/CheckpointTextDocument) when you need a named saved point. A revert changes current content; it is not just a historical read. ## Response Returns **200 OK** with a JSON body. This operation has no continuation cursor. An empty `items` array means no matching visible results were returned. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [Document version](#document-version-response-items) | Yes | Saved versions of the selected text document. This operation has no cursor pagination. | ### Document version · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `version_id` | string | Yes | Saved version identity. Keep it together with the document's file_id to read or restore this version. | | `kind` | string | Yes | How the version was saved: named is a user-labelled checkpoint; auto is an automatic checkpoint, and pre_revert preserves the state before a restore. | | `label` | string or null | Yes | Name supplied for a named checkpoint, or null when no label was recorded. | | `word_count` | number | Yes | Number of words in the saved content. | | `participants` | array of string | No | Account IDs of the people who edited this version. | | `created_by` | string or null | Yes | Account that created the record, or null when no account is recorded. | | `created_at` | number | Yes | Creation time in Unix milliseconds. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | | 409 | `not_text_document` | This file is not a collaborative text document. Use CreateTextDocument or select kind=text_document from ListDocuments. | ## Next steps - [Get text document version](/developers/reference/documents/GetTextDocumentVersion) - [Checkpoint text document](/developers/reference/documents/CheckpointTextDocument) - [Revert text document](/developers/reference/documents/RevertTextDocument) - [Create text document](/developers/reference/documents/CreateTextDocument) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Inspect saved versions These are historical snapshots, not separate files. Keep file_id alongside a selected version_id. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.ListTextDocumentVersions' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "file_id": "f_project_notes" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/documents.ListTextDocumentVersions", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "file_id": "f_project_notes" }), }); 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 payload = { "file_id": "f_project_notes" } request = Request( "https://api.brigg.app/v1/operations/documents.ListTextDocumentVersions", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "version_id": "tdv_project_notes_2", "kind": "named", "label": "Before legal review", "word_count": 7, "participants": [ "a_jamie" ], "created_by": "a_jamie", "created_at": 1794301200000 } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "file_id": { "type": "string", "minLength": 1, "description": "Use the file_id of a collaborative text document. Find an existing document with [ListDocuments](/developers/reference/documents/ListDocuments) and select kind=text_document. An uploaded PDF, Word file or plain-text file is not a collaborative text document. [documents.CreateTextDocument](/developers/reference/documents/CreateTextDocument)." } }, "required": [ "file_id" ], "additionalProperties": false, "examples": [ { "file_id": "f_project_notes" } ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "version_id": { "type": "string", "description": "Saved version identity. Keep it together with the document's file_id to read or restore this version.", "examples": [ "version_proposal_2" ] }, "kind": { "type": "string", "description": "How the version was saved: named is a user-labelled checkpoint; auto is an automatic checkpoint, and pre_revert preserves the state before a restore.", "examples": [ "named" ] }, "label": { "type": [ "string", "null" ], "description": "Name supplied for a named checkpoint, or null when no label was recorded.", "examples": [ "Revised proposal" ] }, "word_count": { "type": "number", "description": "Number of words in the saved content.", "examples": [ 420 ] }, "participants": { "description": "Account IDs of the people who edited this version.", "type": "array", "items": { "type": "string" }, "examples": [ [ "account_alex" ] ] }, "created_by": { "type": [ "string", "null" ], "description": "Account that created the record, or null when no account is recorded.", "examples": [ "account_alex" ] }, "created_at": { "type": "number", "description": "Creation time in Unix milliseconds." } }, "required": [ "version_id", "kind", "label", "word_count", "created_by", "created_at" ], "additionalProperties": false, "title": "Document version" }, "description": "Saved versions of the selected text document. This operation has no cursor pagination." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "version_id": "tdv_project_notes_2", "kind": "named", "label": "Before legal review", "word_count": 7, "participants": [ "a_jamie" ], "created_by": "a_jamie", "created_at": 1794301200000 } ] } ] } ``` --- # Read text document Read a text document’s current Markdown and revision, including live editor changes. POST https://api.brigg.app/v1/operations/documents.ReadTextDocument ## Access & visibility Allow `documents.ReadTextDocument` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `file_id` | string | Yes | Use the file_id of a collaborative text document. Find an existing document with [ListDocuments](/developers/reference/documents/ListDocuments) and select kind=text_document. An uploaded PDF, Word file or plain-text file is not a collaborative text document. [documents.CreateTextDocument](/developers/reference/documents/CreateTextDocument). At least 1 character. | ## Work with text and saved versions All documents use a stable `file_id`. Select `document_kind=text_document` from the listing for these collaborative text operations. [Read text document](/developers/reference/documents/ReadTextDocument) returns its current Markdown and location. For an exact change, use [Edit text document](/developers/reference/documents/EditTextDocument) with the existing text and its replacement; this avoids sending an old full copy over another edit. [Replace text document](/developers/reference/documents/ReplaceTextDocument) replaces the entire Markdown body. Send the read response’s `revision` as `expected_revision` to refuse intervening changes atomically. Re-read before resolving a failed match or revision conflict. A saved `version_id` identifies historical content. List versions before reading or reverting one, and use [Checkpoint text document](/developers/reference/documents/CheckpointTextDocument) when you need a named saved point. A revert changes current content; it is not just a historical read. ## Response Returns **200 OK** with a JSON body. Reads the live editor state before returning Markdown, including recent edits. Use this operation before an exact replacement. GetTextDocumentContent instead reads the last stored projection and can lag behind open editors. | Field | Type | Required | Description | | --- | --- | --- | --- | | `file_id` | string | Yes | The same stable identity supplied as file_id. This response uses camelCase; later requests still use file_id. | | `filename` | string | Yes | Current document name. A collaborative text document is not an uploaded PDF or Word file and does not require a filename extension. | | `scope` | string or null | Yes | Current document collection: org is workspace-shared, user is personal, and resources is the resources collection. Null means no collection is recorded; it does not grant access. This is location metadata, not a request to move the document. | | `path` | string | Yes | Folder path within the current collection. An empty string is the collection root. | | `word_count` | number | Yes | Word count of the returned or saved text, excluding Markdown formatting. | | `revision` | string | Yes | Opaque token identifying this exact content. Pass it as expected_revision to a text edit. It is not a history version_id and cannot be used to select an export version. | | `md` | string | Yes | Document content formatted as Markdown. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | | 409 | `not_text_document` | This file is not a collaborative text document. Use CreateTextDocument or select kind=text_document from ListDocuments. | ## Next steps - [Edit text document](/developers/reference/documents/EditTextDocument) - [Replace text document](/developers/reference/documents/ReplaceTextDocument) - [List text document versions](/developers/reference/documents/ListTextDocumentVersions) - [Create text document](/developers/reference/documents/CreateTextDocument) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Read current text The response identifies the document and includes its current Markdown. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.ReadTextDocument' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "file_id": "f_project_notes" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/documents.ReadTextDocument", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "file_id": "f_project_notes" }), }); 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 payload = { "file_id": "f_project_notes" } request = Request( "https://api.brigg.app/v1/operations/documents.ReadTextDocument", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "file_id": "f_project_notes", "filename": "Project notes", "scope": "org", "path": "Projects", "word_count": 7, "revision": "tdr_before_edit", "md": "# Project notes\n\nThe kickoff is on Tuesday." } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "file_id": { "type": "string", "minLength": 1, "description": "Use the file_id of a collaborative text document. Find an existing document with [ListDocuments](/developers/reference/documents/ListDocuments) and select kind=text_document. An uploaded PDF, Word file or plain-text file is not a collaborative text document. [documents.CreateTextDocument](/developers/reference/documents/CreateTextDocument)." } }, "required": [ "file_id" ], "additionalProperties": false, "examples": [ { "file_id": "f_project_notes" } ] } ``` ```json-schema-response { "type": "object", "properties": { "file_id": { "type": "string", "description": "The same stable identity supplied as file_id. This response uses camelCase; later requests still use file_id." }, "filename": { "type": "string", "description": "Current document name. A collaborative text document is not an uploaded PDF or Word file and does not require a filename extension." }, "scope": { "type": [ "string", "null" ], "description": "Current document collection: org is workspace-shared, user is personal, and resources is the resources collection. Null means no collection is recorded; it does not grant access. This is location metadata, not a request to move the document." }, "path": { "type": "string", "description": "Folder path within the current collection. An empty string is the collection root." }, "word_count": { "type": "number", "description": "Word count of the returned or saved text, excluding Markdown formatting." }, "revision": { "type": "string", "description": "Opaque token identifying this exact content. Pass it as expected_revision to a text edit. It is not a history version_id and cannot be used to select an export version." }, "md": { "type": "string", "description": "Document content formatted as Markdown." } }, "required": [ "file_id", "filename", "scope", "path", "word_count", "revision", "md" ], "additionalProperties": false, "examples": [ { "file_id": "f_project_notes", "filename": "Project notes", "scope": "org", "path": "Projects", "word_count": 7, "revision": "tdr_before_edit", "md": "# Project notes\n\nThe kickoff is on Tuesday." } ] } ``` --- # Checkpoint text document Save a named version of a text document's current content. POST https://api.brigg.app/v1/operations/documents.CheckpointTextDocument ## Access & visibility Allow `documents.CheckpointTextDocument` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `file_id` | string | Yes | Use the file_id of a collaborative text document. Find an existing document with [ListDocuments](/developers/reference/documents/ListDocuments) and select kind=text_document. An uploaded PDF, Word file or plain-text file is not a collaborative text document. [documents.CreateTextDocument](/developers/reference/documents/CreateTextDocument). At least 1 character. | | `label` | string | Yes | Name for this saved point, trimmed before saving. Use a meaningful label such as Before legal review. At least 1 character. At most 120 characters. | ## Work with text and saved versions All documents use a stable `file_id`. Select `document_kind=text_document` from the listing for these collaborative text operations. [Read text document](/developers/reference/documents/ReadTextDocument) returns its current Markdown and location. For an exact change, use [Edit text document](/developers/reference/documents/EditTextDocument) with the existing text and its replacement; this avoids sending an old full copy over another edit. [Replace text document](/developers/reference/documents/ReplaceTextDocument) replaces the entire Markdown body. Send the read response’s `revision` as `expected_revision` to refuse intervening changes atomically. Re-read before resolving a failed match or revision conflict. A saved `version_id` identifies historical content. List versions before reading or reverting one, and use [Checkpoint text document](/developers/reference/documents/CheckpointTextDocument) when you need a named saved point. A revert changes current content; it is not just a historical read. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `version_id` | string or null | Yes | ID of the named snapshot of the current live content. Named checkpoints create a history entry even when the text has not changed. The nullable contract also covers a document disappearing during the save; if null, read the document and its history before claiming a named checkpoint was created. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `not_text_document` | This file is not a collaborative text document. Use CreateTextDocument or select kind=text_document from ListDocuments. | ## Next steps - [List text document versions](/developers/reference/documents/ListTextDocumentVersions) - [Get text document version](/developers/reference/documents/GetTextDocumentVersion) - [Revert text document](/developers/reference/documents/RevertTextDocument) - [Create text document](/developers/reference/documents/CreateTextDocument) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Save a named checkpoint Keep a recognisable point in the document's history before a larger edit. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.CheckpointTextDocument' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "file_id": "f_project_notes", "label": "Before legal review" }' ``` #### TypeScript ```typescript 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/documents.CheckpointTextDocument", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "file_id": "f_project_notes", "label": "Before legal review" }), }); 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 = { "file_id": "f_project_notes", "label": "Before legal review" } request = Request( "https://api.brigg.app/v1/operations/documents.CheckpointTextDocument", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "version_id": "tdv_project_notes_2" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "file_id": { "type": "string", "minLength": 1, "description": "Use the file_id of a collaborative text document. Find an existing document with [ListDocuments](/developers/reference/documents/ListDocuments) and select kind=text_document. An uploaded PDF, Word file or plain-text file is not a collaborative text document. [documents.CreateTextDocument](/developers/reference/documents/CreateTextDocument)." }, "label": { "type": "string", "minLength": 1, "maxLength": 120, "description": "Name for this saved point, trimmed before saving. Use a meaningful label such as Before legal review." } }, "required": [ "file_id", "label" ], "additionalProperties": false, "examples": [ { "file_id": "f_project_notes", "label": "Before legal review" } ] } ``` ```json-schema-response { "type": "object", "properties": { "version_id": { "type": [ "string", "null" ], "description": "ID of the named snapshot of the current live content. Named checkpoints create a history entry even when the text has not changed. The nullable contract also covers a document disappearing during the save; if null, read the document and its history before claiming a named checkpoint was created." } }, "required": [ "version_id" ], "additionalProperties": false, "examples": [ { "version_id": "tdv_project_notes_2" } ] } ``` --- # Convert document to text document Create an editable text document from a plain-text upload or a generated document’s prose, leaving the original unchanged. PDF and Word imports are not supported. POST https://api.brigg.app/v1/operations/documents.ConvertDocumentToTextDocument ## Access & visibility Allow `documents.ConvertDocumentToTextDocument` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `file_id` | string | Yes | Use a file_id returned by this listing or by CompleteUpload. It is not an upload ID, storage path or filename. [documents.ListDocuments](/developers/reference/documents/ListDocuments). At least 1 character. | | `scope` | string | Yes | Document collection: workspace or the acting member's personal collection, as allowed by this operation. Allowed: `"org"`, `"user"`. | | `path` | string | No | Folder path within the selected document collection. An empty string is its root. At most 1024 characters. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `file_id` | string | Yes | Stable file ID returned by documents.CompleteUpload, documents.ListDocuments or a document creation operation. Use the same ID for downloads, attachments and supported file-based workflows. Do not use a filename or storage path. | | `path` | string | Yes | Folder path within the selected document collection. An empty string is its root. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [Upload and download files](/developers/files) - [List documents](/developers/reference/documents/ListDocuments) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.ConvertDocumentToTextDocument' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "file_id": "e_example", "scope": "org" }' ``` #### TypeScript ```typescript 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/documents.ConvertDocumentToTextDocument", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "file_id": "e_example", "scope": "org" }), }); 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 = { "file_id": "e_example", "scope": "org" } request = Request( "https://api.brigg.app/v1/operations/documents.ConvertDocumentToTextDocument", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "file_id": "e_example", "path": "Proposals" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "file_id": { "type": "string", "minLength": 1, "description": "Use a file_id returned by this listing or by CompleteUpload. It is not an upload ID, storage path or filename. [documents.ListDocuments](/developers/reference/documents/ListDocuments)." }, "scope": { "type": "string", "enum": [ "org", "user" ], "description": "Document collection: workspace or the acting member's personal collection, as allowed by this operation." }, "path": { "type": "string", "maxLength": 1024, "description": "Folder path within the selected document collection. An empty string is its root." } }, "required": [ "file_id", "scope" ], "additionalProperties": false, "examples": [ { "file_id": "e_example", "scope": "org" } ] } ``` ```json-schema-response { "type": "object", "properties": { "file_id": { "type": "string", "description": "Stable file ID returned by documents.CompleteUpload, documents.ListDocuments or a document creation operation. Use the same ID for downloads, attachments and supported file-based workflows. Do not use a filename or storage path." }, "path": { "type": "string", "description": "Folder path within the selected document collection. An empty string is its root." } }, "required": [ "file_id", "path" ], "additionalProperties": false, "examples": [ { "file_id": "e_example", "path": "Proposals" } ] } ``` --- # Create text document Create an editable text document from the supplied content. POST https://api.brigg.app/v1/operations/documents.CreateTextDocument ## Access & visibility Allow `documents.CreateTextDocument` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `scope` | string | Yes | org creates a workspace-shared document; user creates one owned by the approved acting member and requires member delegation. Allowed: `"org"`, `"user"`. | | `path` | string | No | Folder path within the selected document collection. An empty string is its root. At most 1024 characters. | | `name` | string | Yes | Document display name, such as Project notes. No file extension is required. At least 1 character. At most 200 characters. | | `md` | string | No | The document's content as markdown. Omit for an empty document. | ## Work with text and saved versions All documents use a stable `file_id`. Select `document_kind=text_document` from the listing for these collaborative text operations. [Read text document](/developers/reference/documents/ReadTextDocument) returns its current Markdown and location. For an exact change, use [Edit text document](/developers/reference/documents/EditTextDocument) with the existing text and its replacement; this avoids sending an old full copy over another edit. [Replace text document](/developers/reference/documents/ReplaceTextDocument) replaces the entire Markdown body. Send the read response’s `revision` as `expected_revision` to refuse intervening changes atomically. Re-read before resolving a failed match or revision conflict. A saved `version_id` identifies historical content. List versions before reading or reverting one, and use [Checkpoint text document](/developers/reference/documents/CheckpointTextDocument) when you need a named saved point. A revert changes current content; it is not just a historical read. ## Response Returns **200 OK** with a JSON body. If content_not_applied is returned, the empty document already exists. Keep details.file_id and fill it with ReplaceTextDocument instead of creating a second document. | Field | Type | Required | Description | | --- | --- | --- | --- | | `file_id` | string | Yes | Stable identity of the new collaborative text document. Use it as file_id in the text-document operations; it is not an upload ID. | | `path` | string | Yes | Folder path within the selected document collection. An empty string is its root. | | `version_id` | string or null | Yes | Version ID of the resulting content, not a backup of the previous text. An automatic save returns null when the content matches the stored projection and no new version is needed. Null is not an empty document or a failed edit. ListTextDocumentVersions discovers saved versions; keep each version_id together with its file_id. | | `revision` | string | No | The new document's content revision. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [Read text document](/developers/reference/documents/ReadTextDocument) - [Edit text document](/developers/reference/documents/EditTextDocument) - [Replace text document](/developers/reference/documents/ReplaceTextDocument) - [List text document versions](/developers/reference/documents/ListTextDocumentVersions) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Create with Markdown The folder path is relative to the selected collection. Keep file_id for subsequent reads and edits. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.CreateTextDocument' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "scope": "org", "path": "Projects", "name": "Project notes", "md": "# Project notes\n\nThe kickoff is on Tuesday." }' ``` #### TypeScript ```typescript 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/documents.CreateTextDocument", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "scope": "org", "path": "Projects", "name": "Project notes", "md": "# Project notes\n\nThe kickoff is on Tuesday." }), }); 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 = { "scope": "org", "path": "Projects", "name": "Project notes", "md": "# Project notes\n\nThe kickoff is on Tuesday." } request = Request( "https://api.brigg.app/v1/operations/documents.CreateTextDocument", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "file_id": "f_project_notes", "path": "Projects", "version_id": "tdv_project_notes_2" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "scope": { "type": "string", "enum": [ "org", "user" ], "description": "org creates a workspace-shared document; user creates one owned by the approved acting member and requires member delegation." }, "path": { "type": "string", "maxLength": 1024, "description": "Folder path within the selected document collection. An empty string is its root." }, "name": { "type": "string", "minLength": 1, "maxLength": 200, "description": "Document display name, such as Project notes. No file extension is required." }, "md": { "type": "string", "description": "The document's content as markdown. Omit for an empty document." } }, "required": [ "scope", "name" ], "additionalProperties": false, "examples": [ { "scope": "org", "path": "Projects", "name": "Project notes", "md": "# Project notes\n\nThe kickoff is on Tuesday." } ] } ``` ```json-schema-response { "type": "object", "properties": { "file_id": { "type": "string", "description": "Stable identity of the new collaborative text document. Use it as file_id in the text-document operations; it is not an upload ID." }, "path": { "type": "string", "description": "Folder path within the selected document collection. An empty string is its root." }, "version_id": { "type": [ "string", "null" ], "description": "Version ID of the resulting content, not a backup of the previous text. An automatic save returns null when the content matches the stored projection and no new version is needed. Null is not an empty document or a failed edit. ListTextDocumentVersions discovers saved versions; keep each version_id together with its file_id." }, "revision": { "type": "string", "description": "The new document's content revision." } }, "required": [ "file_id", "path", "version_id" ], "additionalProperties": false, "examples": [ { "file_id": "f_project_notes", "path": "Projects", "version_id": "tdv_project_notes_2" } ] } ``` --- # Edit text document Change exact text in a collaborative document. Supply the revision you read to reject intervening changes. POST https://api.brigg.app/v1/operations/documents.EditTextDocument ## Access & visibility Allow `documents.EditTextDocument` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `file_id` | string | Yes | Use the file_id of a collaborative text document. Find an existing document with [ListDocuments](/developers/reference/documents/ListDocuments) and select kind=text_document. An uploaded PDF, Word file or plain-text file is not a collaborative text document. [documents.CreateTextDocument](/developers/reference/documents/CreateTextDocument). At least 1 character. | | `old_string` | string | Yes | Exact text from a current ReadTextDocument response. By default it must occur exactly once. At least 1 character. | | `new_string` | string | Yes | Text to replace the matched passage. An empty string removes it. | | `replace_all` | boolean | No | Defaults to false. True replaces every exact match; it does not interpret a regular expression. | | `expected_revision` | string | No | Copy revision from the latest ReadTextDocument response. A concurrent change returns 409 revision_conflict without applying this edit. Re-read, reconcile and submit a new request with a new idempotency key. Omit only when intentionally editing the current content regardless of prior changes. At least 1 character. At most 200 characters. | ## Work with text and saved versions All documents use a stable `file_id`. Select `document_kind=text_document` from the listing for these collaborative text operations. [Read text document](/developers/reference/documents/ReadTextDocument) returns its current Markdown and location. For an exact change, use [Edit text document](/developers/reference/documents/EditTextDocument) with the existing text and its replacement; this avoids sending an old full copy over another edit. [Replace text document](/developers/reference/documents/ReplaceTextDocument) replaces the entire Markdown body. Send the read response’s `revision` as `expected_revision` to refuse intervening changes atomically. Re-read before resolving a failed match or revision conflict. A saved `version_id` identifies historical content. List versions before reading or reverting one, and use [Checkpoint text document](/developers/reference/documents/CheckpointTextDocument) when you need a named saved point. A revert changes current content; it is not just a historical read. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `file_id` | string | Yes | The same stable identity supplied as file_id. This response uses camelCase; later requests still use file_id. | | `filename` | string | Yes | Current document name. A collaborative text document is not an uploaded PDF or Word file and does not require a filename extension. | | `scope` | string or null | Yes | Current document collection: org is workspace-shared, user is personal, and resources is the resources collection. Null means no collection is recorded; it does not grant access. This is location metadata, not a request to move the document. | | `path` | string | Yes | Folder path within the current collection. An empty string is the collection root. | | `word_count` | number | Yes | Word count of the returned or saved text, excluding Markdown formatting. | | `revision` | string | Yes | Opaque token identifying this exact content. Pass it as expected_revision to a text edit. It is not a history version_id and cannot be used to select an export version. | | `version_id` | string or null | Yes | Version ID of the resulting content, not a backup of the previous text. An automatic save returns null when the content matches the stored projection and no new version is needed. Null is not an empty document or a failed edit. ListTextDocumentVersions discovers saved versions; keep each version_id together with its file_id. | | `replacements` | number | Yes | Number of matching passages changed by this edit; this is a result count, not a list of edits. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `not_text_document` | This file is not a collaborative text document. Use CreateTextDocument or select kind=text_document from ListDocuments. | | 409 | `revision_conflict` | The live content changed since expected_revision. No edit was applied. Re-read, reconcile your change and use a new idempotency key. | | 409 | `not_found` | old_string does not occur in the current text. ReadTextDocument again and prepare a new edit. | | 409 | `not_unique` | old_string has more than one match. Inspect details.occurrences; choose a unique passage or deliberately use replace_all. | | 409 | `unchanged` | The replacement does not change the text. Do not retry this edit unchanged. | ## Next steps - [Read text document](/developers/reference/documents/ReadTextDocument) - [Replace text document](/developers/reference/documents/ReplaceTextDocument) - [List text document versions](/developers/reference/documents/ListTextDocumentVersions) - [Create text document](/developers/reference/documents/CreateTextDocument) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Change one passage Read the current document first. This changes Tuesday to Wednesday once. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.EditTextDocument' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "file_id": "f_project_notes", "old_string": "Tuesday", "new_string": "Wednesday", "expected_revision": "tdr_before_edit" }' ``` #### TypeScript ```typescript 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/documents.EditTextDocument", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "file_id": "f_project_notes", "old_string": "Tuesday", "new_string": "Wednesday", "expected_revision": "tdr_before_edit" }), }); 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 = { "file_id": "f_project_notes", "old_string": "Tuesday", "new_string": "Wednesday", "expected_revision": "tdr_before_edit" } request = Request( "https://api.brigg.app/v1/operations/documents.EditTextDocument", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "file_id": "f_project_notes", "filename": "Project notes", "scope": "org", "path": "Projects", "word_count": 7, "revision": "tdr_after_edit", "version_id": "tdv_project_notes_2", "replacements": 1 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "file_id": { "type": "string", "minLength": 1, "description": "Use the file_id of a collaborative text document. Find an existing document with [ListDocuments](/developers/reference/documents/ListDocuments) and select kind=text_document. An uploaded PDF, Word file or plain-text file is not a collaborative text document. [documents.CreateTextDocument](/developers/reference/documents/CreateTextDocument)." }, "old_string": { "type": "string", "minLength": 1, "description": "Exact text from a current ReadTextDocument response. By default it must occur exactly once." }, "new_string": { "type": "string", "description": "Text to replace the matched passage. An empty string removes it." }, "replace_all": { "type": "boolean", "description": "Defaults to false. True replaces every exact match; it does not interpret a regular expression." }, "expected_revision": { "type": "string", "minLength": 1, "maxLength": 200, "description": "Copy revision from the latest ReadTextDocument response. A concurrent change returns 409 revision_conflict without applying this edit. Re-read, reconcile and submit a new request with a new idempotency key. Omit only when intentionally editing the current content regardless of prior changes." } }, "required": [ "file_id", "old_string", "new_string" ], "additionalProperties": false, "examples": [ { "file_id": "f_project_notes", "old_string": "Tuesday", "new_string": "Wednesday", "expected_revision": "tdr_before_edit" } ] } ``` ```json-schema-response { "type": "object", "properties": { "file_id": { "type": "string", "description": "The same stable identity supplied as file_id. This response uses camelCase; later requests still use file_id." }, "filename": { "type": "string", "description": "Current document name. A collaborative text document is not an uploaded PDF or Word file and does not require a filename extension." }, "scope": { "type": [ "string", "null" ], "description": "Current document collection: org is workspace-shared, user is personal, and resources is the resources collection. Null means no collection is recorded; it does not grant access. This is location metadata, not a request to move the document." }, "path": { "type": "string", "description": "Folder path within the current collection. An empty string is the collection root." }, "word_count": { "type": "number", "description": "Word count of the returned or saved text, excluding Markdown formatting." }, "revision": { "type": "string", "description": "Opaque token identifying this exact content. Pass it as expected_revision to a text edit. It is not a history version_id and cannot be used to select an export version." }, "version_id": { "type": [ "string", "null" ], "description": "Version ID of the resulting content, not a backup of the previous text. An automatic save returns null when the content matches the stored projection and no new version is needed. Null is not an empty document or a failed edit. ListTextDocumentVersions discovers saved versions; keep each version_id together with its file_id." }, "replacements": { "type": "number", "description": "Number of matching passages changed by this edit; this is a result count, not a list of edits." } }, "required": [ "file_id", "filename", "scope", "path", "word_count", "revision", "version_id", "replacements" ], "additionalProperties": false, "examples": [ { "file_id": "f_project_notes", "filename": "Project notes", "scope": "org", "path": "Projects", "word_count": 7, "revision": "tdr_after_edit", "version_id": "tdv_project_notes_2", "replacements": 1 } ] } ``` --- # Replace text document Replace a text document’s full Markdown body. Supply the revision you read to protect concurrent edits. POST https://api.brigg.app/v1/operations/documents.ReplaceTextDocument ## Access & visibility Allow `documents.ReplaceTextDocument` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `file_id` | string | Yes | Use the file_id of a collaborative text document. Find an existing document with [ListDocuments](/developers/reference/documents/ListDocuments) and select kind=text_document. An uploaded PDF, Word file or plain-text file is not a collaborative text document. [documents.CreateTextDocument](/developers/reference/documents/CreateTextDocument). At least 1 character. | | `md` | string | Yes | Entire new Markdown body. This replaces all current content; an empty string clears the body. Use EditTextDocument for a targeted change. | | `expected_revision` | string | No | Copy revision from the latest ReadTextDocument response. A concurrent change returns 409 revision_conflict without applying this edit. Re-read, reconcile and submit a new request with a new idempotency key. Omit only when intentionally editing the current content regardless of prior changes. At least 1 character. At most 200 characters. | ## Work with text and saved versions All documents use a stable `file_id`. Select `document_kind=text_document` from the listing for these collaborative text operations. [Read text document](/developers/reference/documents/ReadTextDocument) returns its current Markdown and location. For an exact change, use [Edit text document](/developers/reference/documents/EditTextDocument) with the existing text and its replacement; this avoids sending an old full copy over another edit. [Replace text document](/developers/reference/documents/ReplaceTextDocument) replaces the entire Markdown body. Send the read response’s `revision` as `expected_revision` to refuse intervening changes atomically. Re-read before resolving a failed match or revision conflict. A saved `version_id` identifies historical content. List versions before reading or reverting one, and use [Checkpoint text document](/developers/reference/documents/CheckpointTextDocument) when you need a named saved point. A revert changes current content; it is not just a historical read. ## Response Returns **200 OK** with a JSON body. The live state is checkpointed before replacement, and the new content reaches open editors. With expected_revision, the comparison and replacement happen atomically against the live state. Without it, a full replacement can overwrite intervening edits. | Field | Type | Required | Description | | --- | --- | --- | --- | | `file_id` | string | Yes | The same stable identity supplied as file_id. This response uses camelCase; later requests still use file_id. | | `filename` | string | Yes | Current document name. A collaborative text document is not an uploaded PDF or Word file and does not require a filename extension. | | `scope` | string or null | Yes | Current document collection: org is workspace-shared, user is personal, and resources is the resources collection. Null means no collection is recorded; it does not grant access. This is location metadata, not a request to move the document. | | `path` | string | Yes | Folder path within the current collection. An empty string is the collection root. | | `word_count` | number | Yes | Word count of the returned or saved text, excluding Markdown formatting. | | `revision` | string | Yes | Opaque token identifying this exact content. Pass it as expected_revision to a text edit. It is not a history version_id and cannot be used to select an export version. | | `version_id` | string or null | Yes | Version ID of the resulting content, not a backup of the previous text. An automatic save returns null when the content matches the stored projection and no new version is needed. Null is not an empty document or a failed edit. ListTextDocumentVersions discovers saved versions; keep each version_id together with its file_id. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `not_text_document` | This file is not a collaborative text document. Use CreateTextDocument or select kind=text_document from ListDocuments. | | 409 | `revision_conflict` | The live content changed since expected_revision. No edit was applied. Re-read, reconcile your change and use a new idempotency key. | ## Next steps - [Read text document](/developers/reference/documents/ReadTextDocument) - [Edit text document](/developers/reference/documents/EditTextDocument) - [List text document versions](/developers/reference/documents/ListTextDocumentVersions) - [Create text document](/developers/reference/documents/CreateTextDocument) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Replace the full body This saves the supplied Markdown in the existing document. Its identity and name stay the same. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.ReplaceTextDocument' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "file_id": "f_project_notes", "md": "# Project notes\n\nThe kickoff is on Wednesday.", "expected_revision": "tdr_before_edit" }' ``` #### TypeScript ```typescript 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/documents.ReplaceTextDocument", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "file_id": "f_project_notes", "md": "# Project notes\n\nThe kickoff is on Wednesday.", "expected_revision": "tdr_before_edit" }), }); 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 = { "file_id": "f_project_notes", "md": "# Project notes\n\nThe kickoff is on Wednesday.", "expected_revision": "tdr_before_edit" } request = Request( "https://api.brigg.app/v1/operations/documents.ReplaceTextDocument", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "file_id": "f_project_notes", "filename": "Project notes", "scope": "org", "path": "Projects", "word_count": 7, "revision": "tdr_after_edit", "version_id": "tdv_project_notes_2" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "file_id": { "type": "string", "minLength": 1, "description": "Use the file_id of a collaborative text document. Find an existing document with [ListDocuments](/developers/reference/documents/ListDocuments) and select kind=text_document. An uploaded PDF, Word file or plain-text file is not a collaborative text document. [documents.CreateTextDocument](/developers/reference/documents/CreateTextDocument)." }, "md": { "type": "string", "description": "Entire new Markdown body. This replaces all current content; an empty string clears the body. Use EditTextDocument for a targeted change." }, "expected_revision": { "type": "string", "minLength": 1, "maxLength": 200, "description": "Copy revision from the latest ReadTextDocument response. A concurrent change returns 409 revision_conflict without applying this edit. Re-read, reconcile and submit a new request with a new idempotency key. Omit only when intentionally editing the current content regardless of prior changes." } }, "required": [ "file_id", "md" ], "additionalProperties": false, "examples": [ { "file_id": "f_project_notes", "md": "# Project notes\n\nThe kickoff is on Wednesday.", "expected_revision": "tdr_before_edit" } ] } ``` ```json-schema-response { "type": "object", "properties": { "file_id": { "type": "string", "description": "The same stable identity supplied as file_id. This response uses camelCase; later requests still use file_id." }, "filename": { "type": "string", "description": "Current document name. A collaborative text document is not an uploaded PDF or Word file and does not require a filename extension." }, "scope": { "type": [ "string", "null" ], "description": "Current document collection: org is workspace-shared, user is personal, and resources is the resources collection. Null means no collection is recorded; it does not grant access. This is location metadata, not a request to move the document." }, "path": { "type": "string", "description": "Folder path within the current collection. An empty string is the collection root." }, "word_count": { "type": "number", "description": "Word count of the returned or saved text, excluding Markdown formatting." }, "revision": { "type": "string", "description": "Opaque token identifying this exact content. Pass it as expected_revision to a text edit. It is not a history version_id and cannot be used to select an export version." }, "version_id": { "type": [ "string", "null" ], "description": "Version ID of the resulting content, not a backup of the previous text. An automatic save returns null when the content matches the stored projection and no new version is needed. Null is not an empty document or a failed edit. ListTextDocumentVersions discovers saved versions; keep each version_id together with its file_id." } }, "required": [ "file_id", "filename", "scope", "path", "word_count", "revision", "version_id" ], "additionalProperties": false, "examples": [ { "file_id": "f_project_notes", "filename": "Project notes", "scope": "org", "path": "Projects", "word_count": 7, "revision": "tdr_after_edit", "version_id": "tdv_project_notes_2" } ] } ``` --- # Revert text document Restore a text document to a saved version. The current content is saved as a new version first, so the restoration can be reversed. POST https://api.brigg.app/v1/operations/documents.RevertTextDocument ## Access & visibility Allow `documents.RevertTextDocument` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `file_id` | string | Yes | Use the file_id of a collaborative text document. Find an existing document with [ListDocuments](/developers/reference/documents/ListDocuments) and select kind=text_document. An uploaded PDF, Word file or plain-text file is not a collaborative text document. [documents.CreateTextDocument](/developers/reference/documents/CreateTextDocument). At least 1 character. | | `version_id` | string | Yes | Saved version_id from ListTextDocumentVersions for this same file_id. It is not a different document's ID. At least 1 character. | ## Work with text and saved versions All documents use a stable `file_id`. Select `document_kind=text_document` from the listing for these collaborative text operations. [Read text document](/developers/reference/documents/ReadTextDocument) returns its current Markdown and location. For an exact change, use [Edit text document](/developers/reference/documents/EditTextDocument) with the existing text and its replacement; this avoids sending an old full copy over another edit. [Replace text document](/developers/reference/documents/ReplaceTextDocument) replaces the entire Markdown body. Send the read response’s `revision` as `expected_revision` to refuse intervening changes atomically. Re-read before resolving a failed match or revision conflict. A saved `version_id` identifies historical content. List versions before reading or reverting one, and use [Checkpoint text document](/developers/reference/documents/CheckpointTextDocument) when you need a named saved point. A revert changes current content; it is not just a historical read. ## Response Returns **200 OK** with a JSON body. The result identifies the restored content, not the safety backup. Before restoration, Brigg saves the current content as a separate pre_revert history entry. To undo a restore, find that entry with ListTextDocumentVersions. If the restored text already matches the stored projection, version_id can be null even though the call succeeded. ReadTextDocument confirms the current result. | Field | Type | Required | Description | | --- | --- | --- | --- | | `version_id` | string or null | Yes | Version ID of the resulting content, not a backup of the previous text. An automatic save returns null when the content matches the stored projection and no new version is needed. Null is not an empty document or a failed edit. ListTextDocumentVersions discovers saved versions; keep each version_id together with its file_id. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `not_text_document` | This file is not a collaborative text document. Use CreateTextDocument or select kind=text_document from ListDocuments. | ## Next steps - [Get text document version](/developers/reference/documents/GetTextDocumentVersion) - [List text document versions](/developers/reference/documents/ListTextDocumentVersions) - [Read text document](/developers/reference/documents/ReadTextDocument) - [Create text document](/developers/reference/documents/CreateTextDocument) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Restore a saved version This writes historical content into the live document. Inspect GetTextDocumentVersion first. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.RevertTextDocument' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "file_id": "f_project_notes", "version_id": "tdv_project_notes_2" }' ``` #### TypeScript ```typescript 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/documents.RevertTextDocument", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "file_id": "f_project_notes", "version_id": "tdv_project_notes_2" }), }); 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 = { "file_id": "f_project_notes", "version_id": "tdv_project_notes_2" } request = Request( "https://api.brigg.app/v1/operations/documents.RevertTextDocument", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "version_id": "tdv_project_notes_3" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "file_id": { "type": "string", "minLength": 1, "description": "Use the file_id of a collaborative text document. Find an existing document with [ListDocuments](/developers/reference/documents/ListDocuments) and select kind=text_document. An uploaded PDF, Word file or plain-text file is not a collaborative text document. [documents.CreateTextDocument](/developers/reference/documents/CreateTextDocument)." }, "version_id": { "type": "string", "minLength": 1, "description": "Saved version_id from ListTextDocumentVersions for this same file_id. It is not a different document's ID." } }, "required": [ "file_id", "version_id" ], "additionalProperties": false, "examples": [ { "file_id": "f_project_notes", "version_id": "tdv_project_notes_2" } ] } ``` ```json-schema-response { "type": "object", "properties": { "version_id": { "type": [ "string", "null" ], "description": "Version ID of the resulting content, not a backup of the previous text. An automatic save returns null when the content matches the stored projection and no new version is needed. Null is not an empty document or a failed edit. ListTextDocumentVersions discovers saved versions; keep each version_id together with its file_id." } }, "required": [ "version_id" ], "additionalProperties": false, "examples": [ { "version_id": "tdv_project_notes_3" } ] } ``` --- # Revoke text document share Revoke one text-document link by share_id. Repeating the revocation succeeds without changing other links or the document’s normal permissions. POST https://api.brigg.app/v1/operations/documents.RevokeTextDocumentShare ## Access & visibility Allow `documents.RevokeTextDocumentShare` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `file_id` | string | Yes | Use the file_id of a collaborative text document. Find an existing document with [ListDocuments](/developers/reference/documents/ListDocuments) and select kind=text_document. An uploaded PDF, Word file or plain-text file is not a collaborative text document. [documents.CreateTextDocument](/developers/reference/documents/CreateTextDocument). At least 1 character. | | `share_id` | string | Yes | Non-secret identifier of a share link returned by a share or share-list operation. Use it to revoke that link; it cannot be used to open the document. Treat the separate url value as a bearer credential. At least 1 character. | ## A share link grants access The returned `url` is a bearer link: someone holding it can open the shared content within that link's terms. Keep it out of application logs and analytics. The separate `share_id` identifies a link for management and revocation; it is not sufficient to read content. Sharing a text document uses `file_id`; sharing a generated document uses `document_id` and can name a `version_id`. Do not substitute one ID type for another. Revoking one share link does not remove other links or change the content's underlying workspace/private visibility. ## Response Returns **200 OK** with a JSON body. Use share_id from ShareTextDocument or ListTextDocumentShares, together with the same file_id. An already revoked, expired or unknown share_id returns ok: true as long as the text document itself is accessible. This does not recall copies a recipient already downloaded. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | | 409 | `not_text_document` | This file is not a collaborative text document. Use CreateTextDocument or select kind=text_document from ListDocuments. | ## Next steps - [List text document shares](/developers/reference/documents/ListTextDocumentShares) - [Share text document](/developers/reference/documents/ShareTextDocument) - [Create text document](/developers/reference/documents/CreateTextDocument) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Revoke one link Other share links for this document remain active. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.RevokeTextDocumentShare' \ -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 '{ "file_id": "f_project_notes", "share_id": "share_project_notes" }' ``` #### 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/documents.RevokeTextDocumentShare", { 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({ "file_id": "f_project_notes", "share_id": "share_project_notes" }), }); 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 = { "file_id": "f_project_notes", "share_id": "share_project_notes" } request = Request( "https://api.brigg.app/v1/operations/documents.RevokeTextDocumentShare", 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 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "file_id": { "type": "string", "minLength": 1, "description": "Use the file_id of a collaborative text document. Find an existing document with [ListDocuments](/developers/reference/documents/ListDocuments) and select kind=text_document. An uploaded PDF, Word file or plain-text file is not a collaborative text document. [documents.CreateTextDocument](/developers/reference/documents/CreateTextDocument)." }, "share_id": { "type": "string", "minLength": 1, "description": "Non-secret identifier of a share link returned by a share or share-list operation. Use it to revoke that link; it cannot be used to open the document. Treat the separate url value as a bearer credential." } }, "required": [ "file_id", "share_id" ], "additionalProperties": false, "examples": [ { "file_id": "f_project_notes", "share_id": "share_project_notes" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." } }, "required": [ "ok" ], "additionalProperties": false, "examples": [ { "ok": true } ] } ``` --- # Share text document Create an expiring read-only link to a text document’s current content. Later edits appear through the same link. Anyone holding the URL can read it until expiry or revocation; share_id is only its management identifier. POST https://api.brigg.app/v1/operations/documents.ShareTextDocument ## Access & visibility Allow `documents.ShareTextDocument` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `file_id` | string | Yes | Use the file_id of a collaborative text document. Find an existing document with [ListDocuments](/developers/reference/documents/ListDocuments) and select kind=text_document. An uploaded PDF, Word file or plain-text file is not a collaborative text document. [documents.CreateTextDocument](/developers/reference/documents/CreateTextDocument). At least 1 character. | | `ttl_days` | integer | No | Link lifetime in days from creation. Defaults to 30; choose an integer from 1 through 365. Creating another link does not revoke existing links. Range: 1 to 365. | ## A share link grants access The returned `url` is a bearer link: someone holding it can open the shared content within that link's terms. Keep it out of application logs and analytics. The separate `share_id` identifies a link for management and revocation; it is not sufficient to read content. Sharing a text document uses `file_id`; sharing a generated document uses `document_id` and can name a `version_id`. Do not substitute one ID type for another. Revoking one share link does not remove other links or change the content's underlying workspace/private visibility. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `share_id` | string | Yes | Non-secret identifier of a share link returned by a share or share-list operation. Use it to revoke that link; it cannot be used to open the document. Treat the separate url value as a bearer credential. | | `url` | string | Yes | Read-only bearer link to the document's current content. Later edits appear at this URL. Send only to intended readers and keep it out of logs. | | `expires_at` | number | Yes | Time this share link stops granting access, in Unix milliseconds. Create a new share link if access is needed after expiry. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | | 409 | `not_text_document` | This file is not a collaborative text document. Use CreateTextDocument or select kind=text_document from ListDocuments. | ## Next steps - [Create text document](/developers/reference/documents/CreateTextDocument) - [List documents](/developers/reference/documents/ListDocuments) - [Read text document](/developers/reference/documents/ReadTextDocument) - [List text document shares](/developers/reference/documents/ListTextDocumentShares) - [Revoke text document share](/developers/reference/documents/RevokeTextDocumentShare) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Share for seven days Use an existing collaborative text document. The URL below is fictional and cannot open a real document. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/documents.ShareTextDocument' \ -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 '{ "file_id": "f_project_notes", "ttl_days": 7 }' ``` #### 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/documents.ShareTextDocument", { 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({ "file_id": "f_project_notes", "ttl_days": 7 }), }); 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 = { "file_id": "f_project_notes", "ttl_days": 7 } request = Request( "https://api.brigg.app/v1/operations/documents.ShareTextDocument", 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 { "share_id": "share_project_notes", "url": "https://app.example.com/share/fictional-link?org=o_northstar", "expires_at": 1794906000000 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "file_id": { "type": "string", "minLength": 1, "description": "Use the file_id of a collaborative text document. Find an existing document with [ListDocuments](/developers/reference/documents/ListDocuments) and select kind=text_document. An uploaded PDF, Word file or plain-text file is not a collaborative text document. [documents.CreateTextDocument](/developers/reference/documents/CreateTextDocument)." }, "ttl_days": { "type": "integer", "minimum": 1, "maximum": 365, "description": "Link lifetime in days from creation. Defaults to 30; choose an integer from 1 through 365. Creating another link does not revoke existing links." } }, "required": [ "file_id" ], "additionalProperties": false, "examples": [ { "file_id": "f_project_notes", "ttl_days": 7 } ] } ``` ```json-schema-response { "type": "object", "properties": { "share_id": { "type": "string", "description": "Non-secret identifier of a share link returned by a share or share-list operation. Use it to revoke that link; it cannot be used to open the document. Treat the separate url value as a bearer credential." }, "url": { "type": "string", "description": "Read-only bearer link to the document's current content. Later edits appear at this URL. Send only to intended readers and keep it out of logs." }, "expires_at": { "type": "number", "description": "Time this share link stops granting access, in Unix milliseconds. Create a new share link if access is needed after expiry." } }, "required": [ "share_id", "url", "expires_at" ], "additionalProperties": false, "examples": [ { "share_id": "share_project_notes", "url": "https://app.example.com/share/fictional-link?org=o_northstar", "expires_at": 1794906000000 } ] } ``` --- # List DNS records Read a hosted domain's DNS records, including record values, time-to-live and aliases. POST https://api.brigg.app/v1/operations/domains.ListDnsRecords ## Access & visibility Allow `domains.ListDnsRecords` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | Use the hosted domain's id, not its hostname. [domains.ListHostedDomains](/developers/reference/domains/ListHostedDomains). At least 1 character. At most 80 characters. | ## Read the hosted zone Select the domain's id from [List hosted domains](/developers/reference/domains/ListHostedDomains). The domain must be active and DNS-hosted by Brigg. The response lists stored zone records; it is not a recursive DNS lookup and does not show what every external resolver currently caches. Record names are relative to zone: @ is the apex and www is a subdomain. TTL is in seconds; values contains the complete value set for that name/type pair. An alias can use alias.target instead of ordinary values. When preparing a change with [Set DNS record](/developers/reference/domains/SetDnsRecord), use @ for the apex or a relative name such as www and include every value you want to keep. Brigg-managed zone records, website aliases and certificate records are excluded. Use the website connection operations to manage site aliases. ## Response Returns **200 OK** with a JSON body. This operation has no continuation cursor. An empty `items` array means no matching visible results were returned. | Field | Type | Required | Description | | --- | --- | --- | --- | | `zone` | string | Yes | Hosted DNS zone for these records. | | `items` | array of [DNS record](#dns-record-response-items) | Yes | DNS records in the selected hosted domain's zone. This operation has no cursor pagination. | ### DNS record · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Relative DNS name within zone: @ is the apex, www is the www subdomain. | | `type` | string | Yes | DNS record type, such as A, CNAME, MX or TXT. Allowed: `"A"`, `"AAAA"`, `"CNAME"`, `"MX"`, `"TXT"`. | | `ttl` | number | Yes | Time to live in seconds; resolvers may cache this record for this duration. | | `values` | array of string | Yes | Record values in the format required by type. MX values include priority; TXT values contain the text value. | | `alias` | [object](#response-items-alias) | No | Alias-target configuration when this is an alias record; ordinary records use values. | ### response.items[].alias | Field | Type | Required | Description | | --- | --- | --- | --- | | `target` | string | Yes | DNS target hostname for this alias. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 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. | | 409 | `not_hosted` | The domain must be active with a hosted DNS zone. Inspect ListHostedDomains before retrying. | ## Next steps - [List hosted domains](/developers/reference/domains/ListHostedDomains) - [Set DNS record](/developers/reference/domains/SetDnsRecord) - [Delete DNS record](/developers/reference/domains/DeleteDnsRecord) - [Connect domain to site](/developers/reference/domains/ConnectDomainToSite) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/domains.ListDnsRecords' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Brigg-Act-As: $BRIGG_ACT_AS" \ --data-raw '{ "id": "domain_example" }' ``` #### 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 response = await fetch("https://api.brigg.app/v1/operations/domains.ListDnsRecords", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Brigg-Act-As": actAs, }, body: JSON.stringify({ "id": "domain_example" }), }); 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 payload = { "id": "domain_example" } request = Request( "https://api.brigg.app/v1/operations/domains.ListDnsRecords", 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"], }, 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 { "zone": "example.com", "items": [ { "name": "www", "type": "CNAME", "ttl": 3600, "values": [ "sites.example.net" ] } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "maxLength": 80, "description": "Use the hosted domain's id, not its hostname. [domains.ListHostedDomains](/developers/reference/domains/ListHostedDomains)." } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "domain_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "zone": { "type": "string", "description": "Hosted DNS zone for these records." }, "items": { "type": "array", "items": { "title": "DNS record", "type": "object", "properties": { "name": { "type": "string", "description": "Relative DNS name within zone: @ is the apex, www is the www subdomain.", "examples": [ "www" ] }, "type": { "type": "string", "enum": [ "A", "AAAA", "CNAME", "MX", "TXT" ], "description": "DNS record type, such as A, CNAME, MX or TXT.", "examples": [ "CNAME" ] }, "ttl": { "type": "number", "description": "Time to live in seconds; resolvers may cache this record for this duration.", "examples": [ 3600 ] }, "values": { "type": "array", "items": { "type": "string" }, "description": "Record values in the format required by type. MX values include priority; TXT values contain the text value.", "examples": [ [ "sites.example.net" ] ] }, "alias": { "type": "object", "properties": { "target": { "type": "string", "description": "DNS target hostname for this alias." } }, "required": [ "target" ], "additionalProperties": false, "description": "Alias-target configuration when this is an alias record; ordinary records use values." } }, "required": [ "name", "type", "ttl", "values" ], "additionalProperties": false }, "description": "DNS records in the selected hosted domain's zone. This operation has no cursor pagination." } }, "required": [ "zone", "items" ], "additionalProperties": false, "examples": [ { "zone": "example.com", "items": [ { "name": "www", "type": "CNAME", "ttl": 3600, "values": [ "sites.example.net" ] } ] } ] } ``` --- # Delete DNS record Delete a DNS record set from a hosted domain. Records required for Brigg hosting and certificate validation cannot be deleted. POST https://api.brigg.app/v1/operations/domains.DeleteDnsRecord ## Access & visibility Allow `domains.DeleteDnsRecord` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | Use the hosted domain's id. Read ListDnsRecords before choosing the exact name and type to delete. [domains.ListHostedDomains](/developers/reference/domains/ListHostedDomains). At least 1 character. At most 80 characters. | | `name` | string | Yes | Record name relative to the domain: '@' for the domain itself, 'www', 'mail', '_dmarc', 'selector._domainkey'. At most 253 characters. | | `type` | string | Yes | One of A, AAAA, CNAME, MX, TXT. The apex NS/SOA are Brigg's own and refused `reserved`. At most 8 characters. | ## Change a hosted DNS record set Select the domain's id from [List hosted domains](/developers/reference/domains/ListHostedDomains). The domain must be active and DNS-hosted by Brigg. A website hostname or app ID is not a hosted-domain ID. Set replaces every value for one name/type pair. Read the current set first and include values you want to retain. Delete removes that whole set. Use @ for the apex, www for a subdomain, and bare TXT text without surrounding quotes. MX values contain a numeric priority followed by the mail hostname. TTL is in seconds. A successful response confirms the stored change, not global DNS propagation; caches can retain the old value until its TTL expires. Brigg-managed website aliases, certificate records and zone records are protected. A CNAME cannot coexist with another record type at the same name. Use the website connection operations to manage Brigg-hosted sites. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List hosted domains](/developers/reference/domains/ListHostedDomains) - [List DNS records](/developers/reference/domains/ListDnsRecords) - [Set DNS record](/developers/reference/domains/SetDnsRecord) - [Connect domain to site](/developers/reference/domains/ConnectDomainToSite) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/domains.DeleteDnsRecord' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_example", "name": "www", "type": "CNAME" }' ``` #### TypeScript ```typescript 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/domains.DeleteDnsRecord", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_example", "name": "www", "type": "CNAME" }), }); 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_example", "name": "www", "type": "CNAME" } request = Request( "https://api.brigg.app/v1/operations/domains.DeleteDnsRecord", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "maxLength": 80, "description": "Use the hosted domain's id. Read ListDnsRecords before choosing the exact name and type to delete. [domains.ListHostedDomains](/developers/reference/domains/ListHostedDomains)." }, "name": { "type": "string", "maxLength": 253, "description": "Record name relative to the domain: '@' for the domain itself, 'www', 'mail', '_dmarc', 'selector._domainkey'." }, "type": { "type": "string", "maxLength": 8, "description": "One of A, AAAA, CNAME, MX, TXT. The apex NS/SOA are Brigg's own and refused `reserved`." } }, "required": [ "id", "name", "type" ], "additionalProperties": false, "examples": [ { "id": "e_example", "name": "www", "type": "CNAME" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." } }, "required": [ "ok" ], "additionalProperties": false, "examples": [ { "ok": true } ] } ``` --- # Set DNS record Create or replace a DNS record set for a hosted domain. Brigg-managed hosting and certificate records cannot be changed. POST https://api.brigg.app/v1/operations/domains.SetDnsRecord ## Access & visibility Allow `domains.SetDnsRecord` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | Use the hosted domain's id; record_types and ttl_options in that listing provide supported DNS settings. [domains.ListHostedDomains](/developers/reference/domains/ListHostedDomains). At least 1 character. At most 80 characters. | | `name` | string | Yes | Record name relative to the domain: '@' for the domain itself, 'www', 'mail', '_dmarc', 'selector._domainkey'. At most 253 characters. | | `type` | string | Yes | One of A, AAAA, CNAME, MX, TXT. The apex NS/SOA are Brigg's own and refused `reserved`. At most 8 characters. | | `ttl` | integer | No | Seconds, 60–604800. Default 3600. Default: `3600`. | | `values` | array of string | Yes | ALL values for this name+type — a set is replaced whole. MX values are ' ' ('10 mail.example.com'); TXT values are the bare text (no quotes). At least 1 item. At most 50 items. | ## Change a hosted DNS record set Select the domain's id from [List hosted domains](/developers/reference/domains/ListHostedDomains). The domain must be active and DNS-hosted by Brigg. A website hostname or app ID is not a hosted-domain ID. Set replaces every value for one name/type pair. Read the current set first and include values you want to retain. Delete removes that whole set. Use @ for the apex, www for a subdomain, and bare TXT text without surrounding quotes. MX values contain a numeric priority followed by the mail hostname. TTL is in seconds. A successful response confirms the stored change, not global DNS propagation; caches can retain the old value until its TTL expires. Brigg-managed website aliases, certificate records and zone records are protected. A CNAME cannot coexist with another record type at the same name. Use the website connection operations to manage Brigg-hosted sites. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `record` | [DnsRecord](#dnsrecord-response-record) | Yes | DNS record set after the requested change. | ### DnsRecord · response.record | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Record name relative to the hosted zone; @ names the zone apex. This is the normalized name saved by the service. | | `type` | string | Yes | DNS record type: A, AAAA, CNAME, MX or TXT. Allowed: `"A"`, `"AAAA"`, `"CNAME"`, `"MX"`, `"TXT"`. | | `ttl` | number | Yes | DNS time to live in seconds. | | `values` | array of string | Yes | Values published in this DNS record set; syntax depends on its record type. | | `alias` | [object](#response-record-alias) | No | Alias target used instead of ordinary DNS values, when present. | ### response.record.alias | Field | Type | Required | Description | | --- | --- | --- | --- | | `target` | string | Yes | DNS target hostname for this alias. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List hosted domains](/developers/reference/domains/ListHostedDomains) - [List DNS records](/developers/reference/domains/ListDnsRecords) - [Connect domain to site](/developers/reference/domains/ConnectDomainToSite) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Point a subdomain at a host This replaces the complete www CNAME record set; it is not an append. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/domains.SetDnsRecord' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "domain_example", "name": "www", "type": "CNAME", "ttl": 3600, "values": [ "sites.example.net" ] }' ``` #### TypeScript ```typescript 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/domains.SetDnsRecord", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "domain_example", "name": "www", "type": "CNAME", "ttl": 3600, "values": [ "sites.example.net" ] }), }); 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": "domain_example", "name": "www", "type": "CNAME", "ttl": 3600, "values": [ "sites.example.net" ] } request = Request( "https://api.brigg.app/v1/operations/domains.SetDnsRecord", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "record": { "name": "www", "type": "CNAME", "ttl": 3600, "values": [ "sites.example.net" ] } } ``` ### Set mail routing MX values include priority and hostname. Preserve all destinations you want to keep. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/domains.SetDnsRecord' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "domain_example", "name": "@", "type": "MX", "ttl": 3600, "values": [ "10 mail.example.net", "20 backup.example.net" ] }' ``` #### TypeScript ```typescript 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/domains.SetDnsRecord", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "domain_example", "name": "@", "type": "MX", "ttl": 3600, "values": [ "10 mail.example.net", "20 backup.example.net" ] }), }); 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": "domain_example", "name": "@", "type": "MX", "ttl": 3600, "values": [ "10 mail.example.net", "20 backup.example.net" ] } request = Request( "https://api.brigg.app/v1/operations/domains.SetDnsRecord", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "record": { "name": "@", "type": "MX", "ttl": 3600, "values": [ "10 mail.example.net", "20 backup.example.net" ] } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "maxLength": 80, "description": "Use the hosted domain's id; record_types and ttl_options in that listing provide supported DNS settings. [domains.ListHostedDomains](/developers/reference/domains/ListHostedDomains)." }, "name": { "type": "string", "maxLength": 253, "description": "Record name relative to the domain: '@' for the domain itself, 'www', 'mail', '_dmarc', 'selector._domainkey'." }, "type": { "type": "string", "maxLength": 8, "description": "One of A, AAAA, CNAME, MX, TXT. The apex NS/SOA are Brigg's own and refused `reserved`." }, "ttl": { "type": "integer", "default": 3600, "description": "Seconds, 60–604800. Default 3600." }, "values": { "type": "array", "items": { "type": "string", "maxLength": 4096 }, "minItems": 1, "maxItems": 50, "description": "ALL values for this name+type — a set is replaced whole. MX values are ' ' ('10 mail.example.com'); TXT values are the bare text (no quotes)." } }, "required": [ "id", "name", "type", "values" ], "additionalProperties": false, "examples": [ { "id": "domain_example", "name": "www", "type": "CNAME", "ttl": 3600, "values": [ "sites.example.net" ] } ] } ``` ```json-schema-response { "type": "object", "properties": { "record": { "description": "DNS record set after the requested change.", "title": "DnsRecord", "type": "object", "properties": { "name": { "type": "string", "description": "Record name relative to the hosted zone; @ names the zone apex. This is the normalized name saved by the service." }, "type": { "type": "string", "enum": [ "A", "AAAA", "CNAME", "MX", "TXT" ], "description": "DNS record type: A, AAAA, CNAME, MX or TXT." }, "ttl": { "type": "number", "description": "DNS time to live in seconds." }, "values": { "type": "array", "items": { "type": "string" }, "description": "Values published in this DNS record set; syntax depends on its record type." }, "alias": { "type": "object", "properties": { "target": { "type": "string", "description": "DNS target hostname for this alias." } }, "required": [ "target" ], "additionalProperties": false, "description": "Alias target used instead of ordinary DNS values, when present." } }, "required": [ "name", "type", "ttl", "values" ], "additionalProperties": false } }, "required": [ "record" ], "additionalProperties": false, "examples": [ { "record": { "name": "www", "type": "CNAME", "ttl": 3600, "values": [ "sites.example.net" ] } } ] } ``` --- # List hosted domains List hosted domains, available website connections and outreach domains. POST https://api.brigg.app/v1/operations/domains.ListHostedDomains ## Access & visibility Allow `domains.ListHostedDomains` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/permissions) ## Request No parameters. Send an empty JSON object (`{}`). ## Response Returns **200 OK** with a JSON body. This operation has no continuation cursor. An empty `items` array means no matching visible results were returned. | Field | Type | Required | Description | | --- | --- | --- | --- | | `pool_domains` | array of [ListHostedDomainsPool_domains](#listhosteddomainspool-domains-response-pool-domains) | Yes | Outreach domains associated with the workspace. | | `has_registrant` | boolean | Yes | Whether registrant details have been saved. | | `can_incur_cost` | boolean | Yes | Whether the acting member may perform the billable domain action. | | `balance_nok` | number or null | Yes | Available workspace credit balance in Norwegian kroner. | | `sites` | array of [ListHostedDomainsSites](#listhosteddomainssites-response-sites) | Yes | Websites available for domain connection. | | `search_tlds` | array of string | Yes | Domain endings supported by this search. | | `record_types` | array of string | Yes | DNS record types supported by this operation. | | `ttl_options` | array of number | Yes | Supported DNS time-to-live values in seconds. | | `configured` | boolean | Yes | Whether the requested domain configuration is present. | | `items` | array of [Hosted domain](#hosted-domain-response-items) | Yes | Domains managed for the workspace, with registration and renewal information. This operation has no cursor pagination. | ### ListHostedDomainsPool_domains · response.pool_domains[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Unique identifier. Use the value returned by a create or list operation. | | `domain` | string | Yes | Website hostname, without a scheme or path. | | `status` | string | Yes | Domain provisioning or registration state. | | `expires_at` | null or number | Yes | Expiry time for the returned temporary action or quote, in Unix milliseconds. | | `yearly_price_nok` | number | Yes | Quoted annual price in Norwegian kroner. | | `renewal_state` | string | Yes | Current domain renewal state. | ### ListHostedDomainsSites · response.sites[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `bundle_id` | string | Yes | Bundle identifier. | | `label` | string | Yes | Human-readable label shown for this item; use its ID or key in API calls. | ### Hosted domain · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Hosted domain ID used by domain and DNS operations; different from the domain hostname. | | `domain` | string | Yes | Website hostname, without a scheme or path. | | `tld` | string | Yes | Domain ending, such as no or com. | | `status` | string | Yes | Registration or provisioning state. A registered domain can still need website or DNS configuration. | | `renewal_state` | string | Yes | Current state of the domain's renewal process; separate from its registration status. | | `yearly_price_nok` | number | Yes | Annual domain price in Norwegian kroner. | | `nameservers` | array of string | Yes | Authoritative nameserver hostnames for the domain. | | `registered_at` | null or number | Yes | Registration time in Unix milliseconds, or null before registration completes. | | `expires_at` | null or number | Yes | Registration expiry in Unix milliseconds, or null when unavailable. | | `next_renewal_charge_at` | null or number | Yes | Next planned renewal charge time in Unix milliseconds, or null if none is scheduled. | | `site_bundle_id` | null or string | Yes | Connected website's content ID, or null if this domain is not assigned to a website. | | `last_error` | null or string | Yes | Most recently recorded provisioning or renewal error, or null when no error is recorded. | | `created_at` | number | Yes | Creation time in Unix milliseconds. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 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. | ## Next steps [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/domains.ListHostedDomains' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Brigg-Act-As: $BRIGG_ACT_AS" \ --data-raw '{}' ``` #### 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 response = await fetch("https://api.brigg.app/v1/operations/domains.ListHostedDomains", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Brigg-Act-As": actAs, }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/domains.ListHostedDomains", 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"], }, 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 { "pool_domains": [], "has_registrant": false, "can_incur_cost": false, "balance_nok": null, "sites": [], "search_tlds": [ "com", "no" ], "record_types": [ "A", "AAAA", "CNAME", "TXT" ], "ttl_options": [], "configured": false, "items": [ { "id": "domain_example", "domain": "example.com", "tld": "com", "status": "active", "renewal_state": "ok", "yearly_price_nok": 199, "nameservers": [ "ns1.example.net", "ns2.example.net" ], "registered_at": null, "expires_at": null, "next_renewal_charge_at": null, "site_bundle_id": null, "last_error": null, "created_at": 1794301200000 } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": {}, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "pool_domains": { "type": "array", "items": { "title": "ListHostedDomainsPool_domains", "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier. Use the value returned by a create or list operation." }, "domain": { "type": "string", "description": "Website hostname, without a scheme or path." }, "status": { "type": "string", "description": "Domain provisioning or registration state." }, "expires_at": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Expiry time for the returned temporary action or quote, in Unix milliseconds." }, "yearly_price_nok": { "type": "number", "description": "Quoted annual price in Norwegian kroner." }, "renewal_state": { "type": "string", "description": "Current domain renewal state." } }, "required": [ "id", "domain", "status", "expires_at", "yearly_price_nok", "renewal_state" ], "additionalProperties": false }, "description": "Outreach domains associated with the workspace." }, "has_registrant": { "type": "boolean", "description": "Whether registrant details have been saved." }, "can_incur_cost": { "type": "boolean", "description": "Whether the acting member may perform the billable domain action." }, "balance_nok": { "type": [ "number", "null" ], "description": "Available workspace credit balance in Norwegian kroner." }, "sites": { "type": "array", "items": { "title": "ListHostedDomainsSites", "type": "object", "properties": { "bundle_id": { "type": "string", "description": "Bundle identifier." }, "label": { "type": "string", "description": "Human-readable label shown for this item; use its ID or key in API calls." } }, "required": [ "bundle_id", "label" ], "additionalProperties": false }, "description": "Websites available for domain connection." }, "search_tlds": { "type": "array", "items": { "type": "string" }, "description": "Domain endings supported by this search." }, "record_types": { "type": "array", "items": { "type": "string" }, "description": "DNS record types supported by this operation." }, "ttl_options": { "type": "array", "items": { "type": "number" }, "description": "Supported DNS time-to-live values in seconds." }, "configured": { "type": "boolean", "description": "Whether the requested domain configuration is present." }, "items": { "type": "array", "items": { "title": "Hosted domain", "type": "object", "properties": { "id": { "type": "string", "description": "Hosted domain ID used by domain and DNS operations; different from the domain hostname.", "examples": [ "domain_example" ] }, "domain": { "type": "string", "description": "Website hostname, without a scheme or path.", "examples": [ "example.com" ] }, "tld": { "type": "string", "description": "Domain ending, such as no or com.", "examples": [ "com" ] }, "status": { "type": "string", "description": "Registration or provisioning state. A registered domain can still need website or DNS configuration.", "examples": [ "active" ] }, "renewal_state": { "type": "string", "description": "Current state of the domain's renewal process; separate from its registration status.", "examples": [ "ok" ] }, "yearly_price_nok": { "type": "number", "description": "Annual domain price in Norwegian kroner.", "examples": [ 199 ] }, "nameservers": { "type": "array", "items": { "type": "string" }, "description": "Authoritative nameserver hostnames for the domain.", "examples": [ [ "ns1.example.net", "ns2.example.net" ] ] }, "registered_at": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Registration time in Unix milliseconds, or null before registration completes." }, "expires_at": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Registration expiry in Unix milliseconds, or null when unavailable." }, "next_renewal_charge_at": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Next planned renewal charge time in Unix milliseconds, or null if none is scheduled." }, "site_bundle_id": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Connected website's content ID, or null if this domain is not assigned to a website.", "examples": [ null ] }, "last_error": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Most recently recorded provisioning or renewal error, or null when no error is recorded.", "examples": [ null ] }, "created_at": { "type": "number", "description": "Creation time in Unix milliseconds." } }, "required": [ "id", "domain", "tld", "status", "renewal_state", "yearly_price_nok", "nameservers", "registered_at", "expires_at", "next_renewal_charge_at", "site_bundle_id", "last_error", "created_at" ], "additionalProperties": false }, "description": "Domains managed for the workspace, with registration and renewal information. This operation has no cursor pagination." } }, "required": [ "items", "pool_domains", "has_registrant", "can_incur_cost", "balance_nok", "sites", "search_tlds", "record_types", "ttl_options", "configured" ], "additionalProperties": false, "examples": [ { "pool_domains": [], "has_registrant": false, "can_incur_cost": false, "balance_nok": null, "sites": [], "search_tlds": [ "com", "no" ], "record_types": [ "A", "AAAA", "CNAME", "TXT" ], "ttl_options": [], "configured": false, "items": [ { "id": "domain_example", "domain": "example.com", "tld": "com", "status": "active", "renewal_state": "ok", "yearly_price_nok": 199, "nameservers": [ "ns1.example.net", "ns2.example.net" ], "registered_at": null, "expires_at": null, "next_renewal_charge_at": null, "site_bundle_id": null, "last_error": null, "created_at": 1794301200000 } ] } ] } ``` --- # Search domains Check availability and yearly prices for supported domain endings. unchecked lists candidates whose registry did not respond. POST https://api.brigg.app/v1/operations/domains.SearchDomains ## Access & visibility Allow `domains.SearchDomains` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `query` | string | Yes | A name or a full domain (acme, acme.no). At least 1 character. At most 253 characters. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `label` | string | Yes | Human-readable label shown for this item; use its ID or key in API calls. | | `results` | array of [DomainSearchResult](#domainsearchresult-response-results) | Yes | Availability and price results for the requested domain candidates. | | `unchecked` | array of string | Yes | Domains whose registry did not return an availability result. | ### DomainSearchResult · response.results[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `domain` | string | Yes | Website hostname, without a scheme or path. | | `tld` | string | Yes | Domain ending, such as com or no. | | `available` | boolean | Yes | Whether the registry reports this domain as available to register. Allowed: `false`, `true`. | | `premium` | boolean | Yes | Whether the registry classifies this as a premium-priced domain. Allowed: `false`, `true`. | | `reason` | null or string | Yes | Explanation for the returned availability or setup outcome. | | `yearly_price_nok` | null or number | Yes | Quoted annual price in Norwegian kroner. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 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. | ## Next steps [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/domains.SearchDomains' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Brigg-Act-As: $BRIGG_ACT_AS" \ --data-raw '{ "query": "northstar" }' ``` #### 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 response = await fetch("https://api.brigg.app/v1/operations/domains.SearchDomains", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Brigg-Act-As": actAs, }, body: JSON.stringify({ "query": "northstar" }), }); 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 payload = { "query": "northstar" } request = Request( "https://api.brigg.app/v1/operations/domains.SearchDomains", 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"], }, 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 { "label": "northstar", "results": [], "unchecked": [] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "query": { "type": "string", "minLength": 1, "maxLength": 253, "description": "A name or a full domain (acme, acme.no)." } }, "required": [ "query" ], "additionalProperties": false, "examples": [ { "query": "northstar" } ] } ``` ```json-schema-response { "type": "object", "properties": { "label": { "type": "string", "description": "Human-readable label shown for this item; use its ID or key in API calls." }, "results": { "type": "array", "items": { "title": "DomainSearchResult", "type": "object", "properties": { "domain": { "type": "string", "description": "Website hostname, without a scheme or path." }, "tld": { "type": "string", "description": "Domain ending, such as com or no." }, "available": { "type": "boolean", "enum": [ false, true ], "description": "Whether the registry reports this domain as available to register." }, "premium": { "type": "boolean", "enum": [ false, true ], "description": "Whether the registry classifies this as a premium-priced domain." }, "reason": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Explanation for the returned availability or setup outcome." }, "yearly_price_nok": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Quoted annual price in Norwegian kroner." } }, "required": [ "domain", "tld", "available", "premium", "reason", "yearly_price_nok" ], "additionalProperties": false }, "description": "Availability and price results for the requested domain candidates." }, "unchecked": { "type": "array", "items": { "type": "string" }, "description": "Domains whose registry did not return an availability result." } }, "required": [ "label", "results", "unchecked" ], "additionalProperties": false, "examples": [ { "label": "northstar", "results": [], "unchecked": [] } ] } ``` --- # Dismiss failed domain Remove a failed domain registration from the workspace's domain list. Other registration states cannot be dismissed. POST https://api.brigg.app/v1/operations/domains.DismissFailedDomain ## Access & visibility Allow `domains.DismissFailedDomain` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | Use the failed domain's id. This is not a cancellation door for a registered domain. [domains.ListHostedDomains](/developers/reference/domains/ListHostedDomains). At least 1 character. At most 80 characters. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List hosted domains](/developers/reference/domains/ListHostedDomains) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/domains.DismissFailedDomain' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_example" }' ``` #### TypeScript ```typescript 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/domains.DismissFailedDomain", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_example" }), }); 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_example" } request = Request( "https://api.brigg.app/v1/operations/domains.DismissFailedDomain", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "maxLength": 80, "description": "Use the failed domain's id. This is not a cancellation door for a registered domain. [domains.ListHostedDomains](/developers/reference/domains/ListHostedDomains)." } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." } }, "required": [ "ok" ], "additionalProperties": false, "examples": [ { "ok": true } ] } ``` --- # Get domain registrant Read the saved domain registrant, or suggested company-register details when no registrant is saved. complete indicates whether the details are ready for confirmation. POST https://api.brigg.app/v1/operations/domains.GetDomainRegistrant ## Access & visibility Allow `domains.GetDomainRegistrant` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/permissions) ## Request No parameters. Send an empty JSON object (`{}`). ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `registrant` | [DomainRegistrant](#domainregistrant-response-registrant) | Yes | Company and contact details used for domain registration. | | `saved` | boolean | Yes | Whether the registrant details were saved. | | `complete` | boolean | No | Whether the saved registrant details are complete enough for confirmation. | ### DomainRegistrant · response.registrant | Field | Type | Required | Description | | --- | --- | --- | --- | | `organization` | string | Yes | Legal organization registering the domain. | | `org_number` | string | Yes | Organisation number from the company register, stored as text to preserve leading zeros. | | `name` | string | Yes | Display name. | | `address_line` | string | Yes | Street address of the domain registrant. | | `postal_code` | string | Yes | Postal code as text, preserving leading zeros. | | `city` | string | Yes | Postal town or city. | | `country` | string | Yes | Country associated with the address or record. | | `email` | string | Yes | Email address. | | `phone` | string | Yes | Phone number including its country calling code. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 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. | ## Next steps [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/domains.GetDomainRegistrant' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Brigg-Act-As: $BRIGG_ACT_AS" \ --data-raw '{}' ``` #### 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 response = await fetch("https://api.brigg.app/v1/operations/domains.GetDomainRegistrant", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Brigg-Act-As": actAs, }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/domains.GetDomainRegistrant", 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"], }, 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 { "registrant": { "organization": "Northstar Consulting AS", "org_number": "999999999", "name": "Alex Morgan", "address_line": "Example street 10", "postal_code": "0150", "city": "Oslo", "country": "NO", "email": "alex@example.com", "phone": "+4799999999" }, "saved": true } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": {}, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "registrant": { "description": "Company and contact details used for domain registration.", "title": "DomainRegistrant", "type": "object", "properties": { "organization": { "type": "string", "description": "Legal organization registering the domain." }, "org_number": { "type": "string", "description": "Organisation number from the company register, stored as text to preserve leading zeros." }, "name": { "type": "string", "description": "Display name." }, "address_line": { "type": "string", "description": "Street address of the domain registrant." }, "postal_code": { "type": "string", "description": "Postal code as text, preserving leading zeros." }, "city": { "type": "string", "description": "Postal town or city." }, "country": { "type": "string", "description": "Country associated with the address or record." }, "email": { "type": "string", "description": "Email address." }, "phone": { "type": "string", "description": "Phone number including its country calling code." } }, "required": [ "organization", "org_number", "name", "address_line", "postal_code", "city", "country", "email", "phone" ], "additionalProperties": false }, "saved": { "type": "boolean", "description": "Whether the registrant details were saved." }, "complete": { "type": "boolean", "description": "Whether the saved registrant details are complete enough for confirmation." } }, "required": [ "registrant", "saved" ], "additionalProperties": false, "examples": [ { "registrant": { "organization": "Northstar Consulting AS", "org_number": "999999999", "name": "Alex Morgan", "address_line": "Example street 10", "postal_code": "0150", "city": "Oslo", "country": "NO", "email": "alex@example.com", "phone": "+4799999999" }, "saved": true } ] } ``` --- # Save domain registrant Save the company and contact details used to register domains for the workspace. POST https://api.brigg.app/v1/operations/domains.SaveDomainRegistrant ## Access & visibility Allow `domains.SaveDomainRegistrant` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `organization` | string | Yes | The registered company name, exactly as the register spells it. At most 255 characters. | | `org_number` | string | Yes | Organisation number from the company register, stored as text to preserve leading zeros. At most 32 characters. | | `name` | string | Yes | The contact person. At most 255 characters. | | `address_line` | string | Yes | Street address of the domain registrant. At most 255 characters. | | `postal_code` | string | Yes | Postal code as text, preserving leading zeros. At most 16 characters. | | `city` | string | Yes | Postal town or city. At most 255 characters. | | `country` | string | Yes | ISO 3166-1 alpha-2. At most 2 characters. | | `email` | string | Yes | Email address. At most 255 characters. | | `phone` | string | Yes | With country code (+47 …). At most 32 characters. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `registrant` | [object (2 variants)](#savedomainregistrantregistrant-response-registrant) | Yes | Company and contact details used for domain registration. | | `saved` | boolean | Yes | Whether the registrant details were saved. | | `registrar_error` | string | No | Present when the record saved but the registrar mirror failed; the purchase re-mirrors. | ### SaveDomainRegistrantRegistrant · response.registrant #### Variant 1 | Field | Type | Required | Description | | --- | --- | --- | --- | | `org_id` | string | Yes | Org identifier. | | `organization` | string | Yes | Legal organization registering the domain. | | `org_number` | string | Yes | Organisation number from the company register, stored as text to preserve leading zeros. | | `name` | string | Yes | Display name. | | `address_line` | string | Yes | Street address of the domain registrant. | | `postal_code` | string | Yes | Postal code as text, preserving leading zeros. | | `city` | string | Yes | Postal town or city. | | `country` | string | Yes | Country associated with the address or record. | | `email` | string | Yes | Email address. | | `phone` | string | Yes | Phone number including its country calling code. | #### Variant 2 | Field | Type | Required | Description | | --- | --- | --- | --- | | `org_id` | string | Yes | Org identifier. | | `organization` | string | Yes | Legal organization registering the domain. | | `org_number` | string | Yes | Organisation number from the company register, stored as text to preserve leading zeros. | | `name` | string | Yes | Display name. | | `address_line` | string | Yes | Street address of the domain registrant. | | `postal_code` | string | Yes | Postal code as text, preserving leading zeros. | | `city` | string | Yes | Postal town or city. | | `country` | string | Yes | Country associated with the address or record. | | `email` | string | Yes | Email address. | | `phone` | string | Yes | Phone number including its country calling code. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/domains.SaveDomainRegistrant' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "organization": "Northstar Consulting AS", "org_number": "999999999", "name": "Alex Morgan", "address_line": "Example street 10", "postal_code": "0150", "city": "Oslo", "country": "NO", "email": "alex@example.com", "phone": "+4799999999" }' ``` #### TypeScript ```typescript 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/domains.SaveDomainRegistrant", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "organization": "Northstar Consulting AS", "org_number": "999999999", "name": "Alex Morgan", "address_line": "Example street 10", "postal_code": "0150", "city": "Oslo", "country": "NO", "email": "alex@example.com", "phone": "+4799999999" }), }); 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 = { "organization": "Northstar Consulting AS", "org_number": "999999999", "name": "Alex Morgan", "address_line": "Example street 10", "postal_code": "0150", "city": "Oslo", "country": "NO", "email": "alex@example.com", "phone": "+4799999999" } request = Request( "https://api.brigg.app/v1/operations/domains.SaveDomainRegistrant", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "registrant": { "org_id": "o_example", "organization": "Northstar Consulting AS", "org_number": "999999999", "name": "Alex Morgan", "address_line": "Example street 10", "postal_code": "0150", "city": "Oslo", "country": "NO", "email": "alex@example.com", "phone": "+4799999999" }, "saved": true } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "organization": { "type": "string", "maxLength": 255, "description": "The registered company name, exactly as the register spells it." }, "org_number": { "type": "string", "maxLength": 32, "description": "Organisation number from the company register, stored as text to preserve leading zeros." }, "name": { "type": "string", "maxLength": 255, "description": "The contact person." }, "address_line": { "type": "string", "maxLength": 255, "description": "Street address of the domain registrant." }, "postal_code": { "type": "string", "maxLength": 16, "description": "Postal code as text, preserving leading zeros." }, "city": { "type": "string", "maxLength": 255, "description": "Postal town or city." }, "country": { "type": "string", "maxLength": 2, "description": "ISO 3166-1 alpha-2." }, "email": { "type": "string", "maxLength": 255, "description": "Email address." }, "phone": { "type": "string", "maxLength": 32, "description": "With country code (+47 …)." } }, "required": [ "organization", "org_number", "name", "address_line", "postal_code", "city", "country", "email", "phone" ], "additionalProperties": false, "examples": [ { "organization": "Northstar Consulting AS", "org_number": "999999999", "name": "Alex Morgan", "address_line": "Example street 10", "postal_code": "0150", "city": "Oslo", "country": "NO", "email": "alex@example.com", "phone": "+4799999999" } ] } ``` ```json-schema-response { "type": "object", "properties": { "registrant": { "description": "Company and contact details used for domain registration.", "title": "SaveDomainRegistrantRegistrant", "anyOf": [ { "type": "object", "properties": { "org_id": { "type": "string", "description": "Org identifier." }, "organization": { "type": "string", "description": "Legal organization registering the domain." }, "org_number": { "type": "string", "description": "Organisation number from the company register, stored as text to preserve leading zeros." }, "name": { "type": "string", "description": "Display name." }, "address_line": { "type": "string", "description": "Street address of the domain registrant." }, "postal_code": { "type": "string", "description": "Postal code as text, preserving leading zeros." }, "city": { "type": "string", "description": "Postal town or city." }, "country": { "type": "string", "description": "Country associated with the address or record." }, "email": { "type": "string", "description": "Email address." }, "phone": { "type": "string", "description": "Phone number including its country calling code." } }, "required": [ "org_id", "organization", "org_number", "name", "address_line", "postal_code", "city", "country", "email", "phone" ], "additionalProperties": false }, { "type": "object", "properties": { "org_id": { "type": "string", "description": "Org identifier." }, "organization": { "type": "string", "description": "Legal organization registering the domain." }, "org_number": { "type": "string", "description": "Organisation number from the company register, stored as text to preserve leading zeros." }, "name": { "type": "string", "description": "Display name." }, "address_line": { "type": "string", "description": "Street address of the domain registrant." }, "postal_code": { "type": "string", "description": "Postal code as text, preserving leading zeros." }, "city": { "type": "string", "description": "Postal town or city." }, "country": { "type": "string", "description": "Country associated with the address or record." }, "email": { "type": "string", "description": "Email address." }, "phone": { "type": "string", "description": "Phone number including its country calling code." } }, "required": [ "org_id", "organization", "org_number", "name", "address_line", "postal_code", "city", "country", "email", "phone" ], "additionalProperties": false } ] }, "saved": { "type": "boolean", "description": "Whether the registrant details were saved." }, "registrar_error": { "type": "string", "description": "Present when the record saved but the registrar mirror failed; the purchase re-mirrors." } }, "required": [ "registrant", "saved" ], "additionalProperties": false, "examples": [ { "registrant": { "org_id": "o_example", "organization": "Northstar Consulting AS", "org_number": "999999999", "name": "Alex Morgan", "address_line": "Example street 10", "postal_code": "0150", "city": "Oslo", "country": "NO", "email": "alex@example.com", "phone": "+4799999999" }, "saved": true } ] } ``` --- # List site domains List a website's custom hostnames, certificate status and required DNS configuration. POST https://api.brigg.app/v1/operations/domains.ListSiteDomains ## Access & visibility Allow `domains.ListSiteDomains` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `bundle_id` | string | Yes | Select a website and use its content_id. This is the website identity, not a domain hostname or workspace ID. [workspace.ListBundles](/developers/reference/workspace/ListBundles). At least 1 character. | ## Response Returns **200 OK** with a JSON body. This operation has no continuation cursor. An empty `items` array means no matching visible results were returned. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [Website domain](#website-domain-response-items) | Yes | Custom domains attached to the selected website. This operation has no cursor pagination. | | `target` | string or null | Yes | DNS target hostname for this alias. | ### Website domain · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `host` | string | Yes | Custom hostname attached to this website. | | `cert_status` | string | Yes | TLS certificate provisioning state. It does not independently verify the site's current reachability. | | `validation_name` | null or string | Yes | DNS validation record name to create, or null when no validation record is needed. | | `validation_value` | null or string | Yes | DNS value for validation_name, or null when no validation record is needed. | | `last_error` | null or string | Yes | Latest recorded domain provisioning error, or null when none is recorded. | | `created_at` | number | Yes | Time the hostname was attached, in Unix milliseconds. | | `issued_at` | null or number | Yes | Time its certificate was issued, in Unix milliseconds; null before issuance. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 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. | ## Next steps - [List bundles](/developers/reference/workspace/ListBundles) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/domains.ListSiteDomains' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Brigg-Act-As: $BRIGG_ACT_AS" \ --data-raw '{ "bundle_id": "e_example" }' ``` #### 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 response = await fetch("https://api.brigg.app/v1/operations/domains.ListSiteDomains", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Brigg-Act-As": actAs, }, body: JSON.stringify({ "bundle_id": "e_example" }), }); 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 payload = { "bundle_id": "e_example" } request = Request( "https://api.brigg.app/v1/operations/domains.ListSiteDomains", 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"], }, 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 { "items": [ { "host": "www.example.com", "cert_status": "issued", "validation_name": null, "validation_value": null, "last_error": null, "created_at": 1, "issued_at": null } ], "target": "sites.example.net" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "bundle_id": { "type": "string", "minLength": 1, "description": "Select a website and use its content_id. This is the website identity, not a domain hostname or workspace ID. [workspace.ListBundles](/developers/reference/workspace/ListBundles)." } }, "required": [ "bundle_id" ], "additionalProperties": false, "examples": [ { "bundle_id": "e_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "title": "Website domain", "type": "object", "properties": { "host": { "type": "string", "description": "Custom hostname attached to this website.", "examples": [ "www.example.com" ] }, "cert_status": { "type": "string", "description": "TLS certificate provisioning state. It does not independently verify the site's current reachability.", "examples": [ "issued" ] }, "validation_name": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "DNS validation record name to create, or null when no validation record is needed.", "examples": [ null ] }, "validation_value": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "DNS value for validation_name, or null when no validation record is needed.", "examples": [ null ] }, "last_error": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Latest recorded domain provisioning error, or null when none is recorded.", "examples": [ null ] }, "created_at": { "type": "number", "description": "Time the hostname was attached, in Unix milliseconds." }, "issued_at": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Time its certificate was issued, in Unix milliseconds; null before issuance." } }, "required": [ "host", "cert_status", "validation_name", "validation_value", "last_error", "created_at", "issued_at" ], "additionalProperties": false }, "description": "Custom domains attached to the selected website. This operation has no cursor pagination." }, "target": { "type": [ "string", "null" ], "description": "DNS target hostname for this alias." } }, "required": [ "items", "target" ], "additionalProperties": false, "examples": [ { "items": [ { "host": "www.example.com", "cert_status": "issued", "validation_name": null, "validation_value": null, "last_error": null, "created_at": 1, "issued_at": null } ], "target": "sites.example.net" } ] } ``` --- # Add site domain Connect a custom hostname to a published website and begin certificate setup. The domain owner must add the required DNS records. POST https://api.brigg.app/v1/operations/domains.AddSiteDomain ## Access & visibility Allow `domains.AddSiteDomain` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `bundle_id` | string | Yes | Select a website and use its content_id. This is the website identity, not a domain hostname or workspace ID. [workspace.ListBundles](/developers/reference/workspace/ListBundles). At least 1 character. | | `hostname` | string | Yes | A hostname the customer controls the DNS of (www.acme.no). At least 1 character. At most 253 characters. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | null or [object](#addsitedomainitem-response-item) | Yes | The custom hostname as listed on the bundle, or null when the row could not be read back after the insert. | ### AddSiteDomainItem · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `host` | string | Yes | Custom hostname connected to the website. | | `cert_status` | string | Yes | Current certificate provisioning state. | | `validation_name` | null or string | Yes | DNS name required to validate certificate ownership, when validation is pending. | | `validation_value` | null or string | Yes | DNS value required to validate certificate ownership, when validation is pending. | | `last_error` | null or string | Yes | Most recent setup failure, or null when none is recorded. | | `created_at` | number | Yes | Time this domain configuration was created, in Unix milliseconds. | | `issued_at` | null or number | Yes | Time the certificate was issued, in Unix milliseconds. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | ## Next steps - [List bundles](/developers/reference/workspace/ListBundles) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/domains.AddSiteDomain' \ -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 '{ "bundle_id": "e_example", "hostname": "www.example.com" }' ``` #### 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/domains.AddSiteDomain", { 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({ "bundle_id": "e_example", "hostname": "www.example.com" }), }); 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 = { "bundle_id": "e_example", "hostname": "www.example.com" } request = Request( "https://api.brigg.app/v1/operations/domains.AddSiteDomain", 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 { "item": null } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "bundle_id": { "type": "string", "minLength": 1, "description": "Select a website and use its content_id. This is the website identity, not a domain hostname or workspace ID. [workspace.ListBundles](/developers/reference/workspace/ListBundles)." }, "hostname": { "type": "string", "minLength": 1, "maxLength": 253, "description": "A hostname the customer controls the DNS of (www.acme.no)." } }, "required": [ "bundle_id", "hostname" ], "additionalProperties": false, "examples": [ { "bundle_id": "e_example", "hostname": "www.example.com" } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "description": "The custom hostname as listed on the bundle, or null when the row could not be read back after the insert.", "title": "AddSiteDomainItem", "anyOf": [ { "type": "null" }, { "type": "object", "properties": { "host": { "type": "string", "description": "Custom hostname connected to the website." }, "cert_status": { "type": "string", "description": "Current certificate provisioning state." }, "validation_name": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "DNS name required to validate certificate ownership, when validation is pending." }, "validation_value": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "DNS value required to validate certificate ownership, when validation is pending." }, "last_error": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Most recent setup failure, or null when none is recorded." }, "created_at": { "type": "number", "description": "Time this domain configuration was created, in Unix milliseconds." }, "issued_at": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Time the certificate was issued, in Unix milliseconds." } }, "required": [ "host", "cert_status", "validation_name", "validation_value", "last_error", "created_at", "issued_at" ], "additionalProperties": false } ] } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": null } ] } ``` --- # Connect domain to site Connect a hosted domain and its www subdomain to a published Brigg website. Remove conflicting A, AAAA or CNAME records first. POST https://api.brigg.app/v1/operations/domains.ConnectDomainToSite ## Access & visibility Allow `domains.ConnectDomainToSite` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | Use the hosted domain's id, not a hostname. [domains.ListHostedDomains](/developers/reference/domains/ListHostedDomains). At least 1 character. At most 80 characters. | | `bundle_id` | string | Yes | Select a website and use its content_id. This is the website identity, not a domain hostname or workspace ID. [workspace.ListBundles](/developers/reference/workspace/ListBundles). At least 1 character. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `hosts` | array of string | Yes | The apex and www hosts the site now answers (or no longer answers) on. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List hosted domains](/developers/reference/domains/ListHostedDomains) - [List bundles](/developers/reference/workspace/ListBundles) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/domains.ConnectDomainToSite' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_example", "bundle_id": "e_example" }' ``` #### TypeScript ```typescript 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/domains.ConnectDomainToSite", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_example", "bundle_id": "e_example" }), }); 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_example", "bundle_id": "e_example" } request = Request( "https://api.brigg.app/v1/operations/domains.ConnectDomainToSite", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "hosts": [ "example.com", "www.example.com" ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "maxLength": 80, "description": "Use the hosted domain's id, not a hostname. [domains.ListHostedDomains](/developers/reference/domains/ListHostedDomains)." }, "bundle_id": { "type": "string", "minLength": 1, "description": "Select a website and use its content_id. This is the website identity, not a domain hostname or workspace ID. [workspace.ListBundles](/developers/reference/workspace/ListBundles)." } }, "required": [ "id", "bundle_id" ], "additionalProperties": false, "examples": [ { "id": "e_example", "bundle_id": "e_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "hosts": { "type": "array", "items": { "type": "string" }, "description": "The apex and www hosts the site now answers (or no longer answers) on." } }, "required": [ "hosts" ], "additionalProperties": false, "examples": [ { "hosts": [ "example.com", "www.example.com" ] } ] } ``` --- # Disconnect domain from site Remove a hosted domain's connection to its Brigg website. POST https://api.brigg.app/v1/operations/domains.DisconnectDomainFromSite ## Access & visibility Allow `domains.DisconnectDomainFromSite` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | Use the hosted domain's id for the connection being removed. [domains.ListHostedDomains](/developers/reference/domains/ListHostedDomains). At least 1 character. At most 80 characters. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `hosts` | array of string | Yes | The apex and www hosts the site now answers (or no longer answers) on. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List hosted domains](/developers/reference/domains/ListHostedDomains) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/domains.DisconnectDomainFromSite' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_example" }' ``` #### TypeScript ```typescript 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/domains.DisconnectDomainFromSite", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_example" }), }); 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_example" } request = Request( "https://api.brigg.app/v1/operations/domains.DisconnectDomainFromSite", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "hosts": [ "example.com", "www.example.com" ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "maxLength": 80, "description": "Use the hosted domain's id for the connection being removed. [domains.ListHostedDomains](/developers/reference/domains/ListHostedDomains)." } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "hosts": { "type": "array", "items": { "type": "string" }, "description": "The apex and www hosts the site now answers (or no longer answers) on." } }, "required": [ "hosts" ], "additionalProperties": false, "examples": [ { "hosts": [ "example.com", "www.example.com" ] } ] } ``` --- # Remove site domain Disconnect a custom hostname from a website. The website remains available at its Brigg-hosted address. POST https://api.brigg.app/v1/operations/domains.RemoveSiteDomain ## Access & visibility Allow `domains.RemoveSiteDomain` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `bundle_id` | string | Yes | Select a website and use its content_id. This is the website identity, not a domain hostname or workspace ID. [workspace.ListBundles](/developers/reference/workspace/ListBundles). At least 1 character. | | `host` | string | Yes | The custom hostname, as listed on the bundle. At least 1 character. At most 253 characters. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | ## Next steps - [List bundles](/developers/reference/workspace/ListBundles) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/domains.RemoveSiteDomain' \ -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 '{ "bundle_id": "e_example", "host": "www.example.com" }' ``` #### 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/domains.RemoveSiteDomain", { 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({ "bundle_id": "e_example", "host": "www.example.com" }), }); 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 = { "bundle_id": "e_example", "host": "www.example.com" } request = Request( "https://api.brigg.app/v1/operations/domains.RemoveSiteDomain", 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 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "bundle_id": { "type": "string", "minLength": 1, "description": "Select a website and use its content_id. This is the website identity, not a domain hostname or workspace ID. [workspace.ListBundles](/developers/reference/workspace/ListBundles)." }, "host": { "type": "string", "minLength": 1, "maxLength": 253, "description": "The custom hostname, as listed on the bundle." } }, "required": [ "bundle_id", "host" ], "additionalProperties": false, "examples": [ { "bundle_id": "e_example", "host": "www.example.com" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." } }, "required": [ "ok" ], "additionalProperties": false, "examples": [ { "ok": true } ] } ``` --- # Retry site domain Retry certificate setup for a custom hostname after correcting its DNS configuration. POST https://api.brigg.app/v1/operations/domains.RetrySiteDomain ## Access & visibility Allow `domains.RetrySiteDomain` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `bundle_id` | string | Yes | Select a website and use its content_id. This is the website identity, not a domain hostname or workspace ID. [workspace.ListBundles](/developers/reference/workspace/ListBundles). At least 1 character. | | `host` | string | Yes | The custom hostname, as listed on the bundle. At least 1 character. At most 253 characters. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | ## Next steps - [List bundles](/developers/reference/workspace/ListBundles) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/domains.RetrySiteDomain' \ -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 '{ "bundle_id": "e_example", "host": "www.example.com" }' ``` #### 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/domains.RetrySiteDomain", { 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({ "bundle_id": "e_example", "host": "www.example.com" }), }); 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 = { "bundle_id": "e_example", "host": "www.example.com" } request = Request( "https://api.brigg.app/v1/operations/domains.RetrySiteDomain", 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 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "bundle_id": { "type": "string", "minLength": 1, "description": "Select a website and use its content_id. This is the website identity, not a domain hostname or workspace ID. [workspace.ListBundles](/developers/reference/workspace/ListBundles)." }, "host": { "type": "string", "minLength": 1, "maxLength": 253, "description": "The custom hostname, as listed on the bundle." } }, "required": [ "bundle_id", "host" ], "additionalProperties": false, "examples": [ { "bundle_id": "e_example", "host": "www.example.com" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." } }, "required": [ "ok" ], "additionalProperties": false, "examples": [ { "ok": true } ] } ``` --- # Generate image Generate an image from a prompt using workspace credits. Returns a temporary URL accessible to the caller. If generation is still running, retry with the same request ID to collect the result. POST https://api.brigg.app/v1/operations/images.GenerateImage ## Access & visibility Allow `images.GenerateImage` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `prompt` | string | Yes | What to draw. No words inside the image. At least 1 character. At most 4000 characters. | | `aspect_ratio` | string | No | Requested image proportions, using one of the supported values. Allowed: `"1:1"`, `"2:3"`, `"3:2"`, `"3:4"`, `"4:3"`, `"4:5"`, `"5:4"`, `"9:16"`, `"16:9"`, `"21:9"`. | | `size` | string | No | Resolution; 1K when omitted. Bigger costs the org more. Allowed: `"1K"`, `"2K"`, `"4K"`. | | `reference_files` | array of [object](#request-reference-files) | No | Pictures that steer the generation — a product photo to keep faithful, a sketch, a style to follow. Pictures only, never a document. At most 3 items. | ### request.reference_files[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Display name. At least 1 character. At most 120 characters. | | `media_type` | string | Yes | image/png, image/jpeg, image/gif or image/webp. At least 1 character. | | `data` | string | Yes | The bytes, base64. At least 1 character. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `url` | string | Yes | A short-lived, caller-private download URL for the bytes. | | `ext` | string | Yes | png / jpg / … from the bytes. | | `bytes` | number | No | Size of the generated image in bytes. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | ## Next steps [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/images.GenerateImage' \ -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 '{ "prompt": "A quiet mountain lake at sunrise" }' ``` #### 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/images.GenerateImage", { 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({ "prompt": "A quiet mountain lake at sunrise" }), }); 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 = { "prompt": "A quiet mountain lake at sunrise" } request = Request( "https://api.brigg.app/v1/operations/images.GenerateImage", 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 { "url": "https://example.com", "ext": "png" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "prompt": { "type": "string", "minLength": 1, "maxLength": 4000, "description": "What to draw. No words inside the image." }, "aspect_ratio": { "type": "string", "enum": [ "1:1", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9", "21:9" ], "description": "Requested image proportions, using one of the supported values." }, "size": { "type": "string", "enum": [ "1K", "2K", "4K" ], "description": "Resolution; 1K when omitted. Bigger costs the org more." }, "reference_files": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 120, "description": "Display name." }, "media_type": { "type": "string", "minLength": 1, "description": "image/png, image/jpeg, image/gif or image/webp." }, "data": { "type": "string", "minLength": 1, "description": "The bytes, base64." } }, "required": [ "name", "media_type", "data" ], "additionalProperties": false }, "maxItems": 3, "description": "Pictures that steer the generation — a product photo to keep faithful, a sketch, a style to follow. Pictures only, never a document." } }, "required": [ "prompt" ], "additionalProperties": false, "examples": [ { "prompt": "A quiet mountain lake at sunrise" } ] } ``` ```json-schema-response { "type": "object", "properties": { "url": { "type": "string", "description": "A short-lived, caller-private download URL for the bytes." }, "ext": { "type": "string", "description": "png / jpg / … from the bytes." }, "bytes": { "type": "number", "description": "Size of the generated image in bytes." } }, "required": [ "url", "ext" ], "additionalProperties": false, "examples": [ { "url": "https://example.com", "ext": "png" } ] } ``` --- # List API connections List outbound connections that let Brigg call external APIs, such as an accounting service or a custom warehouse API. Use this to inspect which connections are configured and enabled. Configure connections in Brigg; credentials are never returned. POST https://api.brigg.app/v1/operations/integrations.ListApiConnections ## Access & visibility Allow `integrations.ListApiConnections` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/permissions) ## Request No parameters. Send an empty JSON object (`{}`). ## What this list tells you These are outbound connections: Brigg calls another service through them. They are separate from the workspace API key authenticating this request. An enabled connection is configured for use; it is not a live health check. Create or reconnect connections in Brigg Settings. Secrets are never included. ## Response Returns **200 OK** with a JSON body. This operation has no continuation cursor. An empty `items` array means no matching visible results were returned. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [API connection](#api-connection-response-items) | Yes | All outbound API connections configured for this workspace, including disabled connections, ordered by display name. This operation has no cursor pagination. | ### API connection · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `connection_id` | string | Yes | Stable identifier of this outbound connection. Pass it to [Delete API connection](/developers/reference/integrations/DeleteApiConnection) to remove the connection. | | `name` | string | Yes | Display name assigned to the connection in Brigg. | | `provider` | string or null | Yes | Catalog provider identifier, such as fiken. Null identifies a custom API connection rather than a catalog provider. | | `enabled` | boolean | Yes | Whether Brigg may use this connection for outbound requests. This setting does not confirm that its credentials are valid or that the provider is reachable. | | `access` | string | Yes | Outbound HTTP access allowed through this connection: read_only permits GET and HEAD; full permits supported write methods as well. The provider's own credential permissions still apply. This does not describe the calling Brigg API key's permissions. Allowed: `"read_only"`, `"full"`. | | `created_at` | number | Yes | Creation time in Unix milliseconds. | | `updated_at` | number | Yes | Last update time in Unix milliseconds. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/integrations.ListApiConnections' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{}' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/integrations.ListApiConnections", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/integrations.ListApiConnections", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "connection_id": "fiken", "name": "Fiken accounting", "provider": "fiken", "enabled": true, "access": "read_only", "created_at": 1794301200000, "updated_at": 1794301200000 }, { "connection_id": "warehouse", "name": "Warehouse API", "provider": null, "enabled": false, "access": "full", "created_at": 1794301200000, "updated_at": 1794301200000 } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": {}, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "connection_id": { "type": "string", "description": "Stable identifier of this outbound connection. Pass it to [Delete API connection](/developers/reference/integrations/DeleteApiConnection) to remove the connection." }, "name": { "type": "string", "description": "Display name assigned to the connection in Brigg." }, "provider": { "type": [ "string", "null" ], "description": "Catalog provider identifier, such as fiken. Null identifies a custom API connection rather than a catalog provider." }, "enabled": { "type": "boolean", "description": "Whether Brigg may use this connection for outbound requests. This setting does not confirm that its credentials are valid or that the provider is reachable." }, "access": { "type": "string", "enum": [ "read_only", "full" ], "description": "Outbound HTTP access allowed through this connection: read_only permits GET and HEAD; full permits supported write methods as well. The provider's own credential permissions still apply. This does not describe the calling Brigg API key's permissions." }, "created_at": { "type": "number", "description": "Creation time in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Last update time in Unix milliseconds." } }, "required": [ "connection_id", "name", "provider", "enabled", "access", "created_at", "updated_at" ], "additionalProperties": false, "title": "API connection" }, "description": "All outbound API connections configured for this workspace, including disabled connections, ordered by display name. This operation has no cursor pagination." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "connection_id": "fiken", "name": "Fiken accounting", "provider": "fiken", "enabled": true, "access": "read_only", "created_at": 1794301200000, "updated_at": 1794301200000 }, { "connection_id": "warehouse", "name": "Warehouse API", "provider": null, "enabled": false, "access": "full", "created_at": 1794301200000, "updated_at": 1794301200000 } ] } ] } ``` --- # Delete API connection Remove the API connection identified by connection_id from integrations.ListApiConnections. This prevents Brigg from making new calls through that connection; it does not delete records in the external system. POST https://api.brigg.app/v1/operations/integrations.DeleteApiConnection ## Access & visibility Allow `integrations.DeleteApiConnection` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `connection_id` | string | Yes | Use connection_id from the outbound connection catalogue. This does not identify your calling Brigg API key. [integrations.ListApiConnections](/developers/reference/integrations/ListApiConnections). At least 1 character. At most 41 characters. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List API connections](/developers/reference/integrations/ListApiConnections) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/integrations.DeleteApiConnection' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "connection_id": "e_example" }' ``` #### TypeScript ```typescript 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/integrations.DeleteApiConnection", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "connection_id": "e_example" }), }); 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 = { "connection_id": "e_example" } request = Request( "https://api.brigg.app/v1/operations/integrations.DeleteApiConnection", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "connection_id": { "type": "string", "minLength": 1, "maxLength": 41, "description": "Use connection_id from the outbound connection catalogue. This does not identify your calling Brigg API key. [integrations.ListApiConnections](/developers/reference/integrations/ListApiConnections)." } }, "required": [ "connection_id" ], "additionalProperties": false, "examples": [ { "connection_id": "e_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." } }, "required": [ "ok" ], "additionalProperties": false, "examples": [ { "ok": true } ] } ``` --- # List API keys List active API keys and their labels, key previews, creation times and last-use times. Full secrets are never returned. POST https://api.brigg.app/v1/operations/integrations.ListApiKeys ## Access & visibility Allow `integrations.ListApiKeys` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/permissions) ## Request No parameters. Send an empty JSON object (`{}`). ## Response Returns **200 OK** with a JSON body. This operation has no continuation cursor. An empty `items` array means no matching visible results were returned. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [API key summary](#api-key-summary-response-items) | Yes | Active workspace API keys. Secret keys are represented only by a preview, never their full value. This operation has no cursor pagination. | ### API key summary · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Identifier of the workspace API key. Pass it to [Revoke API key](/developers/reference/integrations/RevokeApiKey). | | `kind` | string | Yes | Key category. A secret key authenticates server requests; a publishable key is for the browser conversion-tracking API. | | `preview` | string | Yes | Abbreviated key value for recognizing the key in settings; it cannot authenticate a request. | | `label` | string or null | Yes | Name assigned when the key was created. Null means no label was supplied. | | `created_at` | number | Yes | Creation time in Unix milliseconds. | | `last_used_at` | number or null | Yes | Time the key was last used, in Unix milliseconds. Null means no use has been recorded. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/integrations.ListApiKeys' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{}' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/integrations.ListApiKeys", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/integrations.ListApiKeys", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "key_warehouse", "kind": "secret", "preview": "brigg_sk_…a1b2", "label": "Warehouse sync", "created_at": 1794301200000, "last_used_at": null } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": {}, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Identifier of the workspace API key. Pass it to [Revoke API key](/developers/reference/integrations/RevokeApiKey).", "examples": [ "key_warehouse" ] }, "kind": { "type": "string", "description": "Key category. A secret key authenticates server requests; a publishable key is for the browser conversion-tracking API.", "examples": [ "secret" ] }, "preview": { "type": "string", "description": "Abbreviated key value for recognizing the key in settings; it cannot authenticate a request.", "examples": [ "brigg_sk_…a1b2" ] }, "label": { "type": [ "string", "null" ], "description": "Name assigned when the key was created. Null means no label was supplied.", "examples": [ "Warehouse sync" ] }, "created_at": { "type": "number", "description": "Creation time in Unix milliseconds." }, "last_used_at": { "type": [ "number", "null" ], "description": "Time the key was last used, in Unix milliseconds. Null means no use has been recorded.", "examples": [ null ] } }, "required": [ "id", "kind", "preview", "label", "created_at", "last_used_at" ], "additionalProperties": false, "title": "API key summary" }, "description": "Active workspace API keys. Secret keys are represented only by a preview, never their full value. This operation has no cursor pagination." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "id": "key_warehouse", "kind": "secret", "preview": "brigg_sk_…a1b2", "label": "Warehouse sync", "created_at": 1794301200000, "last_used_at": null } ] } ] } ``` --- # Revoke API key Revoke a workspace API key immediately. Unknown or already revoked key IDs return not_found. POST https://api.brigg.app/v1/operations/integrations.RevokeApiKey ## Access & visibility Allow `integrations.RevokeApiKey` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | Use the key summary's id. Never send the secret API key as this identifier. [integrations.ListApiKeys](/developers/reference/integrations/ListApiKeys). At least 1 character. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List API keys](/developers/reference/integrations/ListApiKeys) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/integrations.RevokeApiKey' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_example" }' ``` #### TypeScript ```typescript 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/integrations.RevokeApiKey", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_example" }), }); 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_example" } request = Request( "https://api.brigg.app/v1/operations/integrations.RevokeApiKey", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Use the key summary's id. Never send the secret API key as this identifier. [integrations.ListApiKeys](/developers/reference/integrations/ListApiKeys)." } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." } }, "required": [ "ok" ], "additionalProperties": false, "examples": [ { "ok": true } ] } ``` --- # List integrations List connected business systems and their current connection and synchronization state. Follow review_url in Brigg to finish setup, reconnect or inspect failures. Provider configuration, credentials and execution payloads stay private. POST https://api.brigg.app/v1/operations/integrations.ListIntegrations ## Access & visibility Allow `integrations.ListIntegrations` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/permissions) ## Request No parameters. Send an empty JSON object (`{}`). ## Response Returns **200 OK** with a JSON body. This operation has no continuation cursor. An empty `items` array means no matching visible results were returned. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [External integration](#external-integration-response-items) | Yes | Configured workspace integrations with their current setup and synchronization state. This operation has no cursor pagination. | ### External integration · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `connection_id` | string | Yes | Identifier of this configured integration. It is distinct from an API connection ID or MCP server ID. | | `name` | string | Yes | Display name of the configured integration. | | `state` | string | Yes | Setup state: preview is being configured; live is active; paused suspends synchronization; disconnected has no active provider connection. Allowed: `"preview"`, `"live"`, `"paused"`, `"disconnected"`. | | `syncing` | boolean | Yes | Whether a synchronization is currently running. False does not imply a failure. | | `connected_at` | number or null | Yes | Time the integration was configured, in Unix milliseconds. Null means configuration has not completed. | | `review_url` | string | Yes | Brigg settings URL where an administrator reviews and configures the integration. Format: uri. | | `requires_attention` | boolean | Yes | Whether the integration needs a company selection or has a recorded error. Open review_url to inspect and resolve it. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/integrations.ListIntegrations' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{}' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/integrations.ListIntegrations", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/integrations.ListIntegrations", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "connection_id": "accounting", "name": "Accounting integration", "state": "live", "syncing": false, "connected_at": 1794301200000, "review_url": "https://brigg.app/settings/integrations", "requires_attention": false } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": {}, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "connection_id": { "type": "string", "description": "Identifier of this configured integration. It is distinct from an API connection ID or MCP server ID." }, "name": { "type": "string", "description": "Display name of the configured integration." }, "state": { "type": "string", "enum": [ "preview", "live", "paused", "disconnected" ], "description": "Setup state: preview is being configured; live is active; paused suspends synchronization; disconnected has no active provider connection." }, "syncing": { "type": "boolean", "description": "Whether a synchronization is currently running. False does not imply a failure." }, "connected_at": { "type": [ "number", "null" ], "description": "Time the integration was configured, in Unix milliseconds. Null means configuration has not completed." }, "review_url": { "type": "string", "format": "uri", "description": "Brigg settings URL where an administrator reviews and configures the integration." }, "requires_attention": { "type": "boolean", "description": "Whether the integration needs a company selection or has a recorded error. Open review_url to inspect and resolve it." } }, "required": [ "connection_id", "name", "state", "syncing", "connected_at", "review_url", "requires_attention" ], "additionalProperties": false, "title": "External integration" }, "description": "Configured workspace integrations with their current setup and synchronization state. This operation has no cursor pagination." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "connection_id": "accounting", "name": "Accounting integration", "state": "live", "syncing": false, "connected_at": 1794301200000, "review_url": "https://brigg.app/settings/integrations", "requires_attention": false } ] } ] } ``` --- # List MCP servers List external MCP servers that Brigg connects to for tools and data. These are outbound connections, separate from agents connecting to Brigg’s own MCP server. Configure or reconnect servers in Brigg; credentials are never returned. POST https://api.brigg.app/v1/operations/integrations.ListMcpServers ## Access & visibility Allow `integrations.ListMcpServers` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/permissions) ## Request No parameters. Send an empty JSON object (`{}`). ## What this list tells you These are external MCP servers that Brigg calls. To connect your own agent to Brigg, use the [MCP connection guide](/developers/mcp). A stored connection status is not a live connectivity check. ## Response Returns **200 OK** with a JSON body. This operation has no continuation cursor. An empty `items` array means no matching visible results were returned. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [MCP server connection](#mcp-server-connection-response-items) | Yes | External MCP servers configured for Brigg to connect to, including disabled connections. These are distinct from clients connecting to Brigg's MCP server. This operation has no cursor pagination. | ### MCP server connection · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `server_id` | string | Yes | Identifier of this outbound MCP connection. Pass it to [Delete MCP server](/developers/reference/integrations/DeleteMcpServer). | | `name` | string | Yes | Display name of the external MCP server. | | `description` | string or null | Yes | Description configured for this server, or null when none was supplied. | | `enabled` | boolean | Yes | Whether Brigg may connect to this server. This setting alone does not establish that authentication or connectivity works. | | `status` | string | Yes | Most recently recorded connection status; this list does not probe the server live. | | `last_connected_at` | number or null | Yes | Last successful connection time in Unix milliseconds; null if no successful connection has been recorded. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/integrations.ListMcpServers' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{}' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/integrations.ListMcpServers", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/integrations.ListMcpServers", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "server_id": "project-tools", "name": "Project tools", "description": "Search project documentation and tasks.", "enabled": true, "status": "ok", "last_connected_at": 1794301200000 } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": {}, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "server_id": { "type": "string", "description": "Identifier of this outbound MCP connection. Pass it to [Delete MCP server](/developers/reference/integrations/DeleteMcpServer)." }, "name": { "type": "string", "description": "Display name of the external MCP server." }, "description": { "type": [ "string", "null" ], "description": "Description configured for this server, or null when none was supplied." }, "enabled": { "type": "boolean", "description": "Whether Brigg may connect to this server. This setting alone does not establish that authentication or connectivity works." }, "status": { "type": "string", "description": "Most recently recorded connection status; this list does not probe the server live." }, "last_connected_at": { "type": [ "number", "null" ], "description": "Last successful connection time in Unix milliseconds; null if no successful connection has been recorded." } }, "required": [ "server_id", "name", "description", "enabled", "status", "last_connected_at" ], "additionalProperties": false, "title": "MCP server connection" }, "description": "External MCP servers configured for Brigg to connect to, including disabled connections. These are distinct from clients connecting to Brigg's MCP server. This operation has no cursor pagination." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "server_id": "project-tools", "name": "Project tools", "description": "Search project documentation and tasks.", "enabled": true, "status": "ok", "last_connected_at": 1794301200000 } ] } ] } ``` --- # Delete MCP server Remove the MCP server identified by server_id from integrations.ListMcpServers. This prevents Brigg from calling it; it does not delete the server or its external data. POST https://api.brigg.app/v1/operations/integrations.DeleteMcpServer ## Access & visibility Allow `integrations.DeleteMcpServer` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `server_id` | string | Yes | Use server_id of an external MCP server configured in Brigg. This is not a client connected to Brigg's MCP endpoint. [integrations.ListMcpServers](/developers/reference/integrations/ListMcpServers). At least 1 character. At most 64 characters. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List MCP servers](/developers/reference/integrations/ListMcpServers) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/integrations.DeleteMcpServer' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "server_id": "e_example" }' ``` #### TypeScript ```typescript 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/integrations.DeleteMcpServer", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "server_id": "e_example" }), }); 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 = { "server_id": "e_example" } request = Request( "https://api.brigg.app/v1/operations/integrations.DeleteMcpServer", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "server_id": { "type": "string", "minLength": 1, "maxLength": 64, "description": "Use server_id of an external MCP server configured in Brigg. This is not a client connected to Brigg's MCP endpoint. [integrations.ListMcpServers](/developers/reference/integrations/ListMcpServers)." } }, "required": [ "server_id" ], "additionalProperties": false, "examples": [ { "server_id": "e_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." } }, "required": [ "ok" ], "additionalProperties": false, "examples": [ { "ok": true } ] } ``` --- # Get record import Read import progress and see whether work is running, completed, paused or cancelled. A completed job may contain failed rows; inspect its counts and row outcomes. POST https://api.brigg.app/v1/operations/integrations.GetRecordImport ## Access & visibility Allow `integrations.GetRecordImport` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `job_id` | string | Yes | Import job ID returned by StartRecordImport. At least 1 character. | ## Track progress and recover Poll Get record import and page through List record import rows. Row numbers refer to physical input lines, starting at 1. A completed job can include failed rows: inspect the failed count. Validation failures are recorded and skipped; source access, key revocation, quota and service failures pause the job before the unfinished row. Each successful record and its resume position commit together. After addressing a pause, call Resume record import with a **new** idempotency key. A lost response to a particular control request uses that request's original key. A stopped worker can be resumed after its lease expires; a queued job can be safely dispatched again. Cancellation stops subsequent commits and retains previously saved records; cancelled jobs cannot resume. Use the same credential and member context to inspect or control this job. Work never acquires permissions added after it started: every row intersects the original approved grant with current access. If you replace the credential, start a new job with the same external references. The permanent reference matches already imported records even after request receipts expire. Correct invalid rows in a new file, keeping those references; Brigg does not guess a match from email or name. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `job_id` | string | Yes | Stable identifier of this resumable import. | | `operation` | string | Yes | Published Upsert operation applied to every row. | | `file_id` | string | Yes | Immutable NDJSON input file. | | `status` | string | Yes | paused requires ResumeRecordImport after the cause has been addressed. Completed imports may contain failed rows. Allowed: `"queued"`, `"running"`, `"completed"`, `"paused"`, `"cancelled"`. | | `processed` | integer | Yes | Rows with a retained outcome. Minimum: 0. | | `created` | integer | Yes | Rows whose successful upsert created a record. Minimum: 0. | | `updated` | integer | Yes | Rows whose successful upsert matched an existing record. Minimum: 0. | | `failed` | integer | Yes | Invalid or refused rows; inspect ListRecordImportRows and submit corrected rows with the same external references. Minimum: 0. | | `error_code` | string or null | Yes | Reason the job paused, or null. Credentials, source-file access and workspace quotas are checked as the import progresses. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [Start record import](/developers/reference/integrations/StartRecordImport) - [List record import rows](/developers/reference/integrations/ListRecordImportRows) - [Resume record import](/developers/reference/integrations/ResumeRecordImport) - [Cancel record import](/developers/reference/integrations/CancelRecordImport) - [Upsert person](/developers/reference/customers/UpsertPerson) - [Create upload](/developers/reference/documents/CreateUpload) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Customer synchronization Fictional source and job IDs. Use the IDs and exact operation returned for your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/integrations.GetRecordImport' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "job_id": "job_customer_sync" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/integrations.GetRecordImport", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "job_id": "job_customer_sync" }), }); 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 payload = { "job_id": "job_customer_sync" } request = Request( "https://api.brigg.app/v1/operations/integrations.GetRecordImport", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "job_id": "job_customer_sync", "operation": "customers.UpsertPerson", "file_id": "f_customers", "status": "completed", "processed": 1000, "created": 720, "updated": 278, "failed": 2, "error_code": null } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "job_id": { "type": "string", "minLength": 1, "description": "Import job ID returned by StartRecordImport." } }, "required": [ "job_id" ], "additionalProperties": false, "examples": [ { "job_id": "job_customer_sync" } ] } ``` ```json-schema-response { "type": "object", "properties": { "job_id": { "type": "string", "description": "Stable identifier of this resumable import." }, "operation": { "type": "string", "description": "Published Upsert operation applied to every row." }, "file_id": { "type": "string", "description": "Immutable NDJSON input file." }, "status": { "type": "string", "enum": [ "queued", "running", "completed", "paused", "cancelled" ], "description": "paused requires ResumeRecordImport after the cause has been addressed. Completed imports may contain failed rows." }, "processed": { "type": "integer", "minimum": 0, "description": "Rows with a retained outcome." }, "created": { "type": "integer", "minimum": 0, "description": "Rows whose successful upsert created a record." }, "updated": { "type": "integer", "minimum": 0, "description": "Rows whose successful upsert matched an existing record." }, "failed": { "type": "integer", "minimum": 0, "description": "Invalid or refused rows; inspect ListRecordImportRows and submit corrected rows with the same external references." }, "error_code": { "type": [ "string", "null" ], "description": "Reason the job paused, or null. Credentials, source-file access and workspace quotas are checked as the import progresses." } }, "required": [ "job_id", "operation", "file_id", "status", "processed", "created", "updated", "failed", "error_code" ], "additionalProperties": false, "examples": [ { "job_id": "job_customer_sync", "operation": "customers.UpsertPerson", "file_id": "f_customers", "status": "completed", "processed": 1000, "created": 720, "updated": 278, "failed": 2, "error_code": null } ] } ``` --- # List record import rows Read paged outcomes for an import: physical row number, created or updated record ID, or a safe error code. Source row contents are not returned. POST https://api.brigg.app/v1/operations/integrations.ListRecordImportRows ## Access & visibility Allow `integrations.ListRecordImportRows` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `job_id` | string | Yes | Import job ID returned by StartRecordImport. At least 1 character. | | `limit` | integer | No | Maximum number of results to return in this page. Continue with next_cursor when returned. Default: `100`. Greater than 0. | | `cursor` | string | No | Copy next_cursor from the preceding response. Keep the same filters, sort and credential. At least 1 character. | ## Track progress and recover Poll Get record import and page through List record import rows. Row numbers refer to physical input lines, starting at 1. A completed job can include failed rows: inspect the failed count. Validation failures are recorded and skipped; source access, key revocation, quota and service failures pause the job before the unfinished row. Each successful record and its resume position commit together. After addressing a pause, call Resume record import with a **new** idempotency key. A lost response to a particular control request uses that request's original key. A stopped worker can be resumed after its lease expires; a queued job can be safely dispatched again. Cancellation stops subsequent commits and retains previously saved records; cancelled jobs cannot resume. Use the same credential and member context to inspect or control this job. Work never acquires permissions added after it started: every row intersects the original approved grant with current access. If you replace the credential, start a new job with the same external references. The permanent reference matches already imported records even after request receipts expire. Correct invalid rows in a new file, keeping those references; Brigg does not guess a match from email or name. ## Response Returns **200 OK** with a JSON body. An empty `items` array means this page contains no matching visible results. Follow `next_cursor` when present. Results contain row numbers, saved record IDs and error codes, never the original source data. Newly finished rows can appear on later pages; keep polling progress until the job settles. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [Import row](#import-row-response-items) | Yes | Completed row outcomes for this import, ordered by physical input row number. Source contents are never returned. Pass next_cursor as cursor to continue when a next cursor is returned. | | `has_more` | boolean | Yes | More completed row outcomes are currently available. | | `next_cursor` | string or null | Yes | Pass this value as cursor to continue with the same filters, sort and credential. Null when there are no more results. | ### Import row · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `row` | integer | Yes | One-based physical line number in the source file. Minimum: 1. | | `status` | string | Yes | Current state reported for this item. Treat values as extensible unless an enum is declared. Allowed: `"created"`, `"updated"`, `"failed"`. | | `record_id` | string or null | Yes | Saved record ID, or null for a failed row. | | `error_code` | string or null | Yes | Safe refusal code for a failed row, or null. | ## Pagination Pass `next_cursor` as `cursor` on the next request, keeping the same query and acting identity. Stop when `next_cursor` is null. Treat the cursor as opaque; never construct or edit it. ```typescript const query = { "job_id": "job_customer_sync", "limit": 100 }; let cursor; do { const response = await fetch("https://api.brigg.app/v1/operations/integrations.ListRecordImportRows", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ ...query, ...(cursor ? { cursor } : {}) }), }); const page = await response.json(); if (!response.ok) throw new Error(`${response.status}: ${page.message}`); for (const item of page.items) { console.log(item); // Process or upsert each result. } cursor = page.next_cursor; } while (cursor); ``` ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [Start record import](/developers/reference/integrations/StartRecordImport) - [Get record import](/developers/reference/integrations/GetRecordImport) - [Resume record import](/developers/reference/integrations/ResumeRecordImport) - [Cancel record import](/developers/reference/integrations/CancelRecordImport) - [Upsert person](/developers/reference/customers/UpsertPerson) - [Create upload](/developers/reference/documents/CreateUpload) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Customer synchronization Fictional source and job IDs. Use the IDs and exact operation returned for your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/integrations.ListRecordImportRows' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "job_id": "job_customer_sync", "limit": 100 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/integrations.ListRecordImportRows", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "job_id": "job_customer_sync", "limit": 100 }), }); 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 payload = { "job_id": "job_customer_sync", "limit": 100 } request = Request( "https://api.brigg.app/v1/operations/integrations.ListRecordImportRows", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "row": 1, "status": "created", "record_id": "e_alex", "error_code": null }, { "row": 2, "status": "failed", "record_id": null, "error_code": "validation" } ], "has_more": false, "next_cursor": null } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "job_id": { "type": "string", "minLength": 1, "description": "Import job ID returned by StartRecordImport." }, "limit": { "type": "integer", "exclusiveMinimum": 0, "default": 100, "description": "Maximum number of results to return in this page. Continue with next_cursor when returned." }, "cursor": { "type": "string", "minLength": 1, "description": "Copy next_cursor from the preceding response. Keep the same filters, sort and credential." } }, "required": [ "job_id" ], "additionalProperties": false, "examples": [ { "job_id": "job_customer_sync", "limit": 100 } ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "title": "Import row", "properties": { "row": { "type": "integer", "minimum": 1, "description": "One-based physical line number in the source file." }, "status": { "type": "string", "enum": [ "created", "updated", "failed" ], "description": "Current state reported for this item. Treat values as extensible unless an enum is declared." }, "record_id": { "type": [ "string", "null" ], "description": "Saved record ID, or null for a failed row." }, "error_code": { "type": [ "string", "null" ], "description": "Safe refusal code for a failed row, or null." } }, "required": [ "row", "status", "record_id", "error_code" ], "additionalProperties": false }, "description": "Completed row outcomes for this import, ordered by physical input row number. Source contents are never returned. Pass next_cursor as cursor to continue when a next cursor is returned." }, "has_more": { "type": "boolean", "description": "More completed row outcomes are currently available." }, "next_cursor": { "type": [ "string", "null" ], "description": "Pass this value as cursor to continue with the same filters, sort and credential. Null when there are no more results." } }, "required": [ "items", "has_more", "next_cursor" ], "additionalProperties": false, "examples": [ { "items": [ { "row": 1, "status": "created", "record_id": "e_alex", "error_code": null }, { "row": 2, "status": "failed", "record_id": null, "error_code": "validation" } ], "has_more": false, "next_cursor": null } ] } ``` --- # Cancel record import Stop further writes from an import and retain records already saved. Cancelled imports cannot resume; a new import can match those records by their permanent external references. POST https://api.brigg.app/v1/operations/integrations.CancelRecordImport ## Access & visibility Allow `integrations.CancelRecordImport` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `job_id` | string | Yes | Import job ID returned by StartRecordImport. At least 1 character. | ## Track progress and recover Poll Get record import and page through List record import rows. Row numbers refer to physical input lines, starting at 1. A completed job can include failed rows: inspect the failed count. Validation failures are recorded and skipped; source access, key revocation, quota and service failures pause the job before the unfinished row. Each successful record and its resume position commit together. After addressing a pause, call Resume record import with a **new** idempotency key. A lost response to a particular control request uses that request's original key. A stopped worker can be resumed after its lease expires; a queued job can be safely dispatched again. Cancellation stops subsequent commits and retains previously saved records; cancelled jobs cannot resume. Use the same credential and member context to inspect or control this job. Work never acquires permissions added after it started: every row intersects the original approved grant with current access. If you replace the credential, start a new job with the same external references. The permanent reference matches already imported records even after request receipts expire. Correct invalid rows in a new file, keeping those references; Brigg does not guess a match from email or name. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `job_id` | string | Yes | Stable identifier of this resumable import. | | `operation` | string | Yes | Published Upsert operation applied to every row. | | `file_id` | string | Yes | Immutable NDJSON input file. | | `status` | string | Yes | paused requires ResumeRecordImport after the cause has been addressed. Completed imports may contain failed rows. Allowed: `"queued"`, `"running"`, `"completed"`, `"paused"`, `"cancelled"`. | | `processed` | integer | Yes | Rows with a retained outcome. Minimum: 0. | | `created` | integer | Yes | Rows whose successful upsert created a record. Minimum: 0. | | `updated` | integer | Yes | Rows whose successful upsert matched an existing record. Minimum: 0. | | `failed` | integer | Yes | Invalid or refused rows; inspect ListRecordImportRows and submit corrected rows with the same external references. Minimum: 0. | | `error_code` | string or null | Yes | Reason the job paused, or null. Credentials, source-file access and workspace quotas are checked as the import progresses. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [Start record import](/developers/reference/integrations/StartRecordImport) - [Get record import](/developers/reference/integrations/GetRecordImport) - [List record import rows](/developers/reference/integrations/ListRecordImportRows) - [Resume record import](/developers/reference/integrations/ResumeRecordImport) - [Upsert person](/developers/reference/customers/UpsertPerson) - [Create upload](/developers/reference/documents/CreateUpload) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Customer synchronization Fictional source and job IDs. Use the IDs and exact operation returned for your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/integrations.CancelRecordImport' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "job_id": "job_customer_sync" }' ``` #### TypeScript ```typescript 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/integrations.CancelRecordImport", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "job_id": "job_customer_sync" }), }); 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 = { "job_id": "job_customer_sync" } request = Request( "https://api.brigg.app/v1/operations/integrations.CancelRecordImport", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "job_id": "job_customer_sync", "operation": "customers.UpsertPerson", "file_id": "f_customers", "status": "cancelled", "processed": 500, "created": 400, "updated": 99, "failed": 1, "error_code": null } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "job_id": { "type": "string", "minLength": 1, "description": "Import job ID returned by StartRecordImport." } }, "required": [ "job_id" ], "additionalProperties": false, "examples": [ { "job_id": "job_customer_sync" } ] } ``` ```json-schema-response { "type": "object", "properties": { "job_id": { "type": "string", "description": "Stable identifier of this resumable import." }, "operation": { "type": "string", "description": "Published Upsert operation applied to every row." }, "file_id": { "type": "string", "description": "Immutable NDJSON input file." }, "status": { "type": "string", "enum": [ "queued", "running", "completed", "paused", "cancelled" ], "description": "paused requires ResumeRecordImport after the cause has been addressed. Completed imports may contain failed rows." }, "processed": { "type": "integer", "minimum": 0, "description": "Rows with a retained outcome." }, "created": { "type": "integer", "minimum": 0, "description": "Rows whose successful upsert created a record." }, "updated": { "type": "integer", "minimum": 0, "description": "Rows whose successful upsert matched an existing record." }, "failed": { "type": "integer", "minimum": 0, "description": "Invalid or refused rows; inspect ListRecordImportRows and submit corrected rows with the same external references." }, "error_code": { "type": [ "string", "null" ], "description": "Reason the job paused, or null. Credentials, source-file access and workspace quotas are checked as the import progresses." } }, "required": [ "job_id", "operation", "file_id", "status", "processed", "created", "updated", "failed", "error_code" ], "additionalProperties": false, "examples": [ { "job_id": "job_customer_sync", "operation": "customers.UpsertPerson", "file_id": "f_customers", "status": "cancelled", "processed": 500, "created": 400, "updated": 99, "failed": 1, "error_code": null } ] } ``` --- # Resume record import Resume an interrupted import from its first unfinished row after fixing the cause. Previously completed rows stay saved; current permissions can narrow but never enlarge the original grant. POST https://api.brigg.app/v1/operations/integrations.ResumeRecordImport ## Access & visibility Allow `integrations.ResumeRecordImport` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `job_id` | string | Yes | Import job ID returned by StartRecordImport. At least 1 character. | ## Track progress and recover Poll Get record import and page through List record import rows. Row numbers refer to physical input lines, starting at 1. A completed job can include failed rows: inspect the failed count. Validation failures are recorded and skipped; source access, key revocation, quota and service failures pause the job before the unfinished row. Each successful record and its resume position commit together. After addressing a pause, call Resume record import with a **new** idempotency key. A lost response to a particular control request uses that request's original key. A stopped worker can be resumed after its lease expires; a queued job can be safely dispatched again. Cancellation stops subsequent commits and retains previously saved records; cancelled jobs cannot resume. Use the same credential and member context to inspect or control this job. Work never acquires permissions added after it started: every row intersects the original approved grant with current access. If you replace the credential, start a new job with the same external references. The permanent reference matches already imported records even after request receipts expire. Correct invalid rows in a new file, keeping those references; Brigg does not guess a match from email or name. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `job_id` | string | Yes | Stable identifier of this resumable import. | | `operation` | string | Yes | Published Upsert operation applied to every row. | | `file_id` | string | Yes | Immutable NDJSON input file. | | `status` | string | Yes | paused requires ResumeRecordImport after the cause has been addressed. Completed imports may contain failed rows. Allowed: `"queued"`, `"running"`, `"completed"`, `"paused"`, `"cancelled"`. | | `processed` | integer | Yes | Rows with a retained outcome. Minimum: 0. | | `created` | integer | Yes | Rows whose successful upsert created a record. Minimum: 0. | | `updated` | integer | Yes | Rows whose successful upsert matched an existing record. Minimum: 0. | | `failed` | integer | Yes | Invalid or refused rows; inspect ListRecordImportRows and submit corrected rows with the same external references. Minimum: 0. | | `error_code` | string or null | Yes | Reason the job paused, or null. Credentials, source-file access and workspace quotas are checked as the import progresses. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `import_cancelled` | A cancelled job cannot resume. Start a new import using the same external references for records already saved. | ## Next steps - [Start record import](/developers/reference/integrations/StartRecordImport) - [Get record import](/developers/reference/integrations/GetRecordImport) - [List record import rows](/developers/reference/integrations/ListRecordImportRows) - [Cancel record import](/developers/reference/integrations/CancelRecordImport) - [Upsert person](/developers/reference/customers/UpsertPerson) - [Create upload](/developers/reference/documents/CreateUpload) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Customer synchronization Fictional source and job IDs. Use the IDs and exact operation returned for your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/integrations.ResumeRecordImport' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "job_id": "job_customer_sync" }' ``` #### TypeScript ```typescript 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/integrations.ResumeRecordImport", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "job_id": "job_customer_sync" }), }); 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 = { "job_id": "job_customer_sync" } request = Request( "https://api.brigg.app/v1/operations/integrations.ResumeRecordImport", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "job_id": "job_customer_sync", "operation": "customers.UpsertPerson", "file_id": "f_customers", "status": "queued", "processed": 500, "created": 400, "updated": 99, "failed": 1, "error_code": null } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "job_id": { "type": "string", "minLength": 1, "description": "Import job ID returned by StartRecordImport." } }, "required": [ "job_id" ], "additionalProperties": false, "examples": [ { "job_id": "job_customer_sync" } ] } ``` ```json-schema-response { "type": "object", "properties": { "job_id": { "type": "string", "description": "Stable identifier of this resumable import." }, "operation": { "type": "string", "description": "Published Upsert operation applied to every row." }, "file_id": { "type": "string", "description": "Immutable NDJSON input file." }, "status": { "type": "string", "enum": [ "queued", "running", "completed", "paused", "cancelled" ], "description": "paused requires ResumeRecordImport after the cause has been addressed. Completed imports may contain failed rows." }, "processed": { "type": "integer", "minimum": 0, "description": "Rows with a retained outcome." }, "created": { "type": "integer", "minimum": 0, "description": "Rows whose successful upsert created a record." }, "updated": { "type": "integer", "minimum": 0, "description": "Rows whose successful upsert matched an existing record." }, "failed": { "type": "integer", "minimum": 0, "description": "Invalid or refused rows; inspect ListRecordImportRows and submit corrected rows with the same external references." }, "error_code": { "type": [ "string", "null" ], "description": "Reason the job paused, or null. Credentials, source-file access and workspace quotas are checked as the import progresses." } }, "required": [ "job_id", "operation", "file_id", "status", "processed", "created", "updated", "failed", "error_code" ], "additionalProperties": false, "examples": [ { "job_id": "job_customer_sync", "operation": "customers.UpsertPerson", "file_id": "f_customers", "status": "queued", "processed": 500, "created": 400, "updated": 99, "failed": 1, "error_code": null } ] } ``` --- # Start record import Start a resumable import from an uploaded NDJSON file. Apply one approved Upsert operation to each row, using permanent external references to avoid duplicate records. Returns a job ID for progress and row outcomes. POST https://api.brigg.app/v1/operations/integrations.StartRecordImport ## Access & visibility Allow `integrations.StartRecordImport` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `file_id` | string | Yes | Uploaded NDJSON file ID. Each physical line is one JSON request body; CSV must be converted first. At least 1 character. | | `operation` | string | Yes | Published generated Upsert operation, such as customers.UpsertPerson. This credential must separately grant that operation and its resource type. At least 1 character. | ## Prepare, upload and start Use a published **generated Upsert** operation for the target resource. Business commands with authored or platform handlers cannot be imported this way. Approve both Start record import and that exact Upsert operation on the credential, including its resource read/write grants. Create a UTF-8 NDJSON file: one complete Upsert request per physical line, with no header or surrounding array. For example: ```json {"external_ref":{"namespace":"crm-production","id":"person-1042"},"data":{"display_name":"Alex Morgan","email":"alex@example.com"}} {"external_ref":{"namespace":"crm-production","id":"person-1043"},"data":{"display_name":"Sam Lee","email":"sam@example.com"}} ``` [Upload the file](/developers/files), then supply its returned file_id and the operation name. Brigg reads the pinned upload version. A private source file requires private:true on every row; choose workspace visibility for a file intended to create shared records. CSV/TSV must be converted to this explicit format first; contact preparation can help with contact-specific mapping. ## Track progress and recover Poll Get record import and page through List record import rows. Row numbers refer to physical input lines, starting at 1. A completed job can include failed rows: inspect the failed count. Validation failures are recorded and skipped; source access, key revocation, quota and service failures pause the job before the unfinished row. Each successful record and its resume position commit together. After addressing a pause, call Resume record import with a **new** idempotency key. A lost response to a particular control request uses that request's original key. A stopped worker can be resumed after its lease expires; a queued job can be safely dispatched again. Cancellation stops subsequent commits and retains previously saved records; cancelled jobs cannot resume. Use the same credential and member context to inspect or control this job. Work never acquires permissions added after it started: every row intersects the original approved grant with current access. If you replace the credential, start a new job with the same external references. The permanent reference matches already imported records even after request receipts expire. Correct invalid rows in a new file, keeping those references; Brigg does not guess a match from email or name. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `job_id` | string | Yes | Stable identifier of this resumable import. | | `operation` | string | Yes | Published Upsert operation applied to every row. | | `file_id` | string | Yes | Immutable NDJSON input file. | | `status` | string | Yes | paused requires ResumeRecordImport after the cause has been addressed. Completed imports may contain failed rows. Allowed: `"queued"`, `"running"`, `"completed"`, `"paused"`, `"cancelled"`. | | `processed` | integer | Yes | Rows with a retained outcome. Minimum: 0. | | `created` | integer | Yes | Rows whose successful upsert created a record. Minimum: 0. | | `updated` | integer | Yes | Rows whose successful upsert matched an existing record. Minimum: 0. | | `failed` | integer | Yes | Invalid or refused rows; inspect ListRecordImportRows and submit corrected rows with the same external references. Minimum: 0. | | `error_code` | string or null | Yes | Reason the job paused, or null. Credentials, source-file access and workspace quotas are checked as the import progresses. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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` | Grant both Start record import and the target Upsert operation, with its required resources and member context. | | 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. | | 422 | `upsert_operation_required` | Choose an available generated Upsert operation, not a Create operation or an authored business command. | | 422 | `immutable_upload_required` | Complete the file upload first and pass its returned file_id. | ## Next steps - [Get record import](/developers/reference/integrations/GetRecordImport) - [List record import rows](/developers/reference/integrations/ListRecordImportRows) - [Resume record import](/developers/reference/integrations/ResumeRecordImport) - [Cancel record import](/developers/reference/integrations/CancelRecordImport) - [Upsert person](/developers/reference/customers/UpsertPerson) - [Create upload](/developers/reference/documents/CreateUpload) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Customer synchronization Fictional source and job IDs. Use the IDs and exact operation returned for your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/integrations.StartRecordImport' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "file_id": "f_customers", "operation": "customers.UpsertPerson" }' ``` #### TypeScript ```typescript 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/integrations.StartRecordImport", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "file_id": "f_customers", "operation": "customers.UpsertPerson" }), }); 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 = { "file_id": "f_customers", "operation": "customers.UpsertPerson" } request = Request( "https://api.brigg.app/v1/operations/integrations.StartRecordImport", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "job_id": "job_customer_sync", "operation": "customers.UpsertPerson", "file_id": "f_customers", "status": "queued", "processed": 0, "created": 0, "updated": 0, "failed": 0, "error_code": null } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "file_id": { "type": "string", "minLength": 1, "description": "Uploaded NDJSON file ID. Each physical line is one JSON request body; CSV must be converted first." }, "operation": { "type": "string", "minLength": 1, "description": "Published generated Upsert operation, such as customers.UpsertPerson. This credential must separately grant that operation and its resource type." } }, "required": [ "file_id", "operation" ], "additionalProperties": false, "examples": [ { "file_id": "f_customers", "operation": "customers.UpsertPerson" } ] } ``` ```json-schema-response { "type": "object", "properties": { "job_id": { "type": "string", "description": "Stable identifier of this resumable import." }, "operation": { "type": "string", "description": "Published Upsert operation applied to every row." }, "file_id": { "type": "string", "description": "Immutable NDJSON input file." }, "status": { "type": "string", "enum": [ "queued", "running", "completed", "paused", "cancelled" ], "description": "paused requires ResumeRecordImport after the cause has been addressed. Completed imports may contain failed rows." }, "processed": { "type": "integer", "minimum": 0, "description": "Rows with a retained outcome." }, "created": { "type": "integer", "minimum": 0, "description": "Rows whose successful upsert created a record." }, "updated": { "type": "integer", "minimum": 0, "description": "Rows whose successful upsert matched an existing record." }, "failed": { "type": "integer", "minimum": 0, "description": "Invalid or refused rows; inspect ListRecordImportRows and submit corrected rows with the same external references." }, "error_code": { "type": [ "string", "null" ], "description": "Reason the job paused, or null. Credentials, source-file access and workspace quotas are checked as the import progresses." } }, "required": [ "job_id", "operation", "file_id", "status", "processed", "created", "updated", "failed", "error_code" ], "additionalProperties": false, "examples": [ { "job_id": "job_customer_sync", "operation": "customers.UpsertPerson", "file_id": "f_customers", "status": "queued", "processed": 0, "created": 0, "updated": 0, "failed": 0, "error_code": null } ] } ``` --- # Get dictionary entry Read a dictionary entry by ID. Returns item: null when no visible record matches. POST https://api.brigg.app/v1/operations/meetings.GetDictionaryEntry ## Access & visibility Allow `meetings.GetDictionaryEntry` on your API key. Resource read permissions: `core:DictionaryEntry`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:DictionaryEntry` record. Use the relevant list operation to discover records. Use the record's top-level `id`, not a business field or account ID. | ## Response Returns **200 OK** with a JSON body. `item: null` means there is no matching record visible to this caller. It does not reveal whether an inaccessible record exists. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. Dictionary entries help meeting transcription recognize names and specialist terms. phrase is the spelling to keep; sounds_like supplies alternative pronunciations. Editing the dictionary does not rewrite previously saved transcripts. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [DictionaryEntryRecord](#dictionaryentryrecord-response-item) or null | Yes | null when no such record | ### DictionaryEntryRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:DictionaryEntry record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [DictionaryEntry](#dictionaryentry-response-item-data) | Yes | The record's fields. | ### DictionaryEntry · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `phrase` | string | Yes | Correct spelling of the name or term to recognize. | | `sounds_like` | array of string | No | Alternative phonetic spellings used to recognize the phrase in speech. | | `language` | string | No | Recognition language code, for example en for English or no for Norwegian. Omit when the term is not tied to a language. This field is an open string, not a closed enum. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [List dictionary entries](/developers/reference/meetings/ListDictionaryEntries) - [Create dictionary entry](/developers/reference/meetings/CreateDictionaryEntry) - [Upsert dictionary entry](/developers/reference/meetings/UpsertDictionaryEntry) - [Update dictionary entry](/developers/reference/meetings/UpdateDictionaryEntry) - [Delete dictionary entry](/developers/reference/meetings/DeleteDictionaryEntry) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.GetDictionaryEntry' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "e_dictionaryentry_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/meetings.GetDictionaryEntry", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "id": "e_dictionaryentry_example" }), }); 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 payload = { "id": "e_dictionaryentry_example" } request = Request( "https://api.brigg.app/v1/operations/meetings.GetDictionaryEntry", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "item": { "id": "e_dictionaryentry_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "phrase": "Northstar", "sounds_like": [ "north star" ], "language": "en" } } } ``` ### No visible record A missing or inaccessible record returns item: null. Do not treat this as proof that a record exists for another member. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.GetDictionaryEntry' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "e_dictionaryentry_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/meetings.GetDictionaryEntry", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "id": "e_dictionaryentry_example" }), }); 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 payload = { "id": "e_dictionaryentry_example" } request = Request( "https://api.brigg.app/v1/operations/meetings.GetDictionaryEntry", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "item": null } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:DictionaryEntry` record. Use the relevant list operation to discover records. Use the record's top-level `id`, not a business field or account ID." } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_dictionaryentry_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": [ "object", "null" ], "properties": { "id": { "type": "string", "description": "Stable core:DictionaryEntry record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "phrase": { "type": "string", "description": "Correct spelling of the name or term to recognize." }, "sounds_like": { "type": "array", "items": { "type": "string" }, "description": "Alternative phonetic spellings used to recognize the phrase in speech." }, "language": { "type": "string", "description": "Recognition language code, for example en for English or no for Norwegian. Omit when the term is not tied to a language. This field is an open string, not a closed enum." } }, "required": [ "phrase" ], "additionalProperties": false, "description": "The record's fields.", "title": "DictionaryEntry" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "null when no such record", "title": "DictionaryEntryRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_dictionaryentry_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "phrase": "Northstar", "sounds_like": [ "north star" ], "language": "en" } } } ] } ``` --- # List dictionary entries List dictionary entries visible to the credential, with filtering, sorting and cursor pagination. POST https://api.brigg.app/v1/operations/meetings.ListDictionaryEntries ## Access & visibility Allow `meetings.ListDictionaryEntries` on your API key. Resource read permissions: `core:DictionaryEntry`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `filters` | array of [object](#request-filters) | No | Conditions the row must ALL satisfy. | | `sort` | [object](#request-sort) | No | Sort order for the results. Defaults to updated_at descending, with id as a tie-breaker. | | `limit` | integer | No | Maximum number of results to return in this page. Continue with next_cursor when returned. Default: `100`. Minimum: 1. | | `cursor` | string | No | The `next_cursor` of the previous page. | ### request.filters[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | `data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private. Allowed: `"id"`, `"created_at"`, `"updated_at"`, `"created_by"`, `"private"`, `"data.phrase"`, `"data.sounds_like"`, `"data.language"`. | | `op` | string | Yes | Comparison operator. Use in with an array, or omit value for is_empty and is_not_empty. Allowed: `"eq"`, `"neq"`, `"contains"`, `"starts_with"`, `"gt"`, `"gte"`, `"lt"`, `"lte"`, `"in"`, `"has"`, `"is_empty"`, `"is_not_empty"`. | | `value` | JSON value | No | The comparison value; an array for `in`; omitted for is_empty / is_not_empty. | ### request.sort | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | `data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private. Allowed: `"id"`, `"created_at"`, `"updated_at"`, `"created_by"`, `"private"`, `"data.phrase"`, `"data.sounds_like"`, `"data.language"`. | | `direction` | string | No | Sort direction: asc for ascending or desc for descending. Allowed: `"asc"`, `"desc"`. | ## Filtering and sorting All conditions are combined with **AND**. Address business fields as `data.`, and record metadata as `id`, `created_at`, `updated_at`, `created_by` or `private`. A field path names one field; it does not traverse nested objects. | Operator | Meaning | Value | | --- | --- | --- | | `eq` | Equal to a scalar | String, number, boolean or null | | `neq` | Not equal; missing values also match | String, number, boolean or null | | `contains` | Case-insensitive text contains | String; % and _ are literal characters | | `starts_with` | Case-insensitive text prefix | String | | `gt`, `gte` | Greater than / at least | Number or string appropriate to the field | | `lt`, `lte` | Less than / at most | Number or string appropriate to the field | | `in` | Equal to any supplied scalar | Nonempty array of strings, numbers, booleans or null | | `has` | Array contains a string | One string; does not match properties inside array objects | | `is_empty` | Missing, null, empty string or empty array | Omit value | | `is_not_empty` | Has a nonempty value | Omit value | Match the stored field's type. Numeric business timestamps take Unix milliseconds; date-only business fields take `YYYY-MM-DD`. The record metadata fields `created_at` and `updated_at` also accept ISO timestamps for ordered comparisons. Sorting defaults to `updated_at` descending. If you supply `sort.field` without `sort.direction`, direction is `desc`. The record ID breaks ties; missing values sort last. ## Response Returns **200 OK** with a JSON body. An empty `items` array means this page contains no matching visible results. Follow `next_cursor` when present. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. Dictionary entries help meeting transcription recognize names and specialist terms. phrase is the spelling to keep; sounds_like supplies alternative pronunciations. Editing the dictionary does not rewrite previously saved transcripts. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [DictionaryEntryRecord](#dictionaryentryrecord-response-items) | Yes | Records visible under the credential's grants and the selected data scope, matching the requested filters. Pass next_cursor as cursor to continue when a next cursor is returned. | | `next_cursor` | string | No | Pass this value as cursor to continue with the same filters, sort and credential. Omitted when there are no more results. | ### DictionaryEntryRecord · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:DictionaryEntry record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [DictionaryEntry](#dictionaryentry-response-items-data) | Yes | The record's fields. | ### DictionaryEntry · response.items[].data | Field | Type | Required | Description | | --- | --- | --- | --- | | `phrase` | string | Yes | Correct spelling of the name or term to recognize. | | `sounds_like` | array of string | No | Alternative phonetic spellings used to recognize the phrase in speech. | | `language` | string | No | Recognition language code, for example en for English or no for Norwegian. Omit when the term is not tied to a language. This field is an open string, not a closed enum. | ## Pagination Pass `next_cursor` from the response as `cursor` on the next request. Keep the same filters, sort and acting identity. Stop when `next_cursor` is absent; do not infer completion from the number of items. The default page size is **100**; `limit` must be a positive integer. **Pagination is a live view, not a snapshot.** Changes between pages can move records across page boundaries. Upsert by record ID rather than appending blindly. For recurring synchronization, use an overlapping update window and deduplicate records. Periodically reconcile IDs to detect deletions. [Resource webhooks](/developers/webhooks) can supplement synchronization for eligible workspace-shared records only: they do not export private or project-scoped records. Personal data still needs polling and reconciliation. ```typescript const query = { "limit": 10 }; let cursor; do { const response = await fetch("https://api.brigg.app/v1/operations/meetings.ListDictionaryEntries", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ ...query, ...(cursor ? { cursor } : {}) }), }); const page = await response.json(); if (!response.ok) throw new Error(`${response.status}: ${page.message}`); for (const item of page.items) { console.log(item); // Process or upsert each result. } cursor = page.next_cursor; } while (cursor); ``` ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | | 400 | `cursor_invalid` | Restart pagination with no cursor. | | 400 | `cursor_mismatch` | Use the cursor with the original filters, sort order and credential. | ## Next steps - [Get dictionary entry](/developers/reference/meetings/GetDictionaryEntry) - [Create dictionary entry](/developers/reference/meetings/CreateDictionaryEntry) - [Upsert dictionary entry](/developers/reference/meetings/UpsertDictionaryEntry) - [Update dictionary entry](/developers/reference/meetings/UpdateDictionaryEntry) - [Delete dictionary entry](/developers/reference/meetings/DeleteDictionaryEntry) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### First page Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.ListDictionaryEntries' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "limit": 10 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/meetings.ListDictionaryEntries", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "limit": 10 }), }); 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 payload = { "limit": 10 } request = Request( "https://api.brigg.app/v1/operations/meetings.ListDictionaryEntries", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_dictionaryentry_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "phrase": "Northstar", "sounds_like": [ "north star" ], "language": "en" } } ] } ``` ### Pronunciation guidance for English Match the language stored on the dictionary entries. These entries guide speech recognition, not text translation. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.ListDictionaryEntries' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "limit": 50, "filters": [ { "field": "data.language", "op": "eq", "value": "en" } ] }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/meetings.ListDictionaryEntries", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "limit": 50, "filters": [ { "field": "data.language", "op": "eq", "value": "en" } ] }), }); 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 payload = { "limit": 50, "filters": [ { "field": "data.language", "op": "eq", "value": "en" } ] } request = Request( "https://api.brigg.app/v1/operations/meetings.ListDictionaryEntries", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_dictionaryentry_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "phrase": "Northstar", "sounds_like": [ "north star" ], "language": "en" } } ] } ``` ### Records updated since a checkpoint 6 October 2026 at 00:00 UTC. Use an overlap window and upsert by ID when synchronizing. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.ListDictionaryEntries' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/meetings.ListDictionaryEntries", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 }), }); 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 payload = { "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 } request = Request( "https://api.brigg.app/v1/operations/meetings.ListDictionaryEntries", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_dictionaryentry_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "phrase": "Northstar", "sounds_like": [ "north star" ], "language": "en" } } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "filters": { "type": "array", "items": { "type": "object", "properties": { "field": { "type": "string", "description": "`data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private.", "enum": [ "id", "created_at", "updated_at", "created_by", "private", "data.phrase", "data.sounds_like", "data.language" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "contains", "starts_with", "gt", "gte", "lt", "lte", "in", "has", "is_empty", "is_not_empty" ], "description": "Comparison operator. Use in with an array, or omit value for is_empty and is_not_empty." }, "value": { "description": "The comparison value; an array for `in`; omitted for is_empty / is_not_empty." } }, "required": [ "field", "op" ], "additionalProperties": false }, "description": "Conditions the row must ALL satisfy." }, "sort": { "type": "object", "properties": { "field": { "type": "string", "description": "`data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private.", "enum": [ "id", "created_at", "updated_at", "created_by", "private", "data.phrase", "data.sounds_like", "data.language" ] }, "direction": { "type": "string", "enum": [ "asc", "desc" ], "description": "Sort direction: asc for ascending or desc for descending." } }, "required": [ "field" ], "additionalProperties": false, "description": "Sort order for the results. Defaults to updated_at descending, with id as a tie-breaker." }, "limit": { "type": "integer", "minimum": 1, "default": 100, "description": "Maximum number of results to return in this page. Continue with next_cursor when returned." }, "cursor": { "type": "string", "description": "The `next_cursor` of the previous page." } }, "additionalProperties": false, "examples": [ { "limit": 10 } ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:DictionaryEntry record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "phrase": { "type": "string", "description": "Correct spelling of the name or term to recognize." }, "sounds_like": { "type": "array", "items": { "type": "string" }, "description": "Alternative phonetic spellings used to recognize the phrase in speech." }, "language": { "type": "string", "description": "Recognition language code, for example en for English or no for Norwegian. Omit when the term is not tied to a language. This field is an open string, not a closed enum." } }, "required": [ "phrase" ], "additionalProperties": false, "description": "The record's fields.", "title": "DictionaryEntry" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "title": "DictionaryEntryRecord" }, "description": "Records visible under the credential's grants and the selected data scope, matching the requested filters. Pass next_cursor as cursor to continue when a next cursor is returned." }, "next_cursor": { "type": "string", "description": "Pass this value as cursor to continue with the same filters, sort and credential. Omitted when there are no more results." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "id": "e_dictionaryentry_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "phrase": "Northstar", "sounds_like": [ "north star" ], "language": "en" } } ] } ] } ``` --- # Create dictionary entry Create a dictionary entry and return the saved record. POST https://api.brigg.app/v1/operations/meetings.CreateDictionaryEntry ## Access & visibility Allow `meetings.CreateDictionaryEntry` on your API key. Resource read permissions: `core:DictionaryEntry`. Resource write permissions: `core:DictionaryEntry`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `data` | [DictionaryEntry](#dictionaryentry-request-data) | Yes | The record's fields. | | `private` | boolean | No | Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance. | ### DictionaryEntry · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `phrase` | string | Yes | Correct spelling of the name or term to recognize. | | `sounds_like` | array of string | No | Alternative phonetic spellings used to recognize the phrase in speech. | | `language` | string | No | Recognition language code, for example en for English or no for Norwegian. Omit when the term is not tied to a language. This field is an open string, not a closed enum. | ## Choose ownership deliberately Omitting `private`, or setting it to false, creates a workspace-shared record. Set `private: true` to create a record owned by the approved acting member. Private records require member delegation; a workspace-only credential cannot own a personal record. The credential’s exact resource grants authorize the write; private ownership and project membership remain enforced. A create is a new record, not an upsert. Reuse the same idempotency key only for retries of that logical creation. For recurring synchronization, use the resource’s upsert operation when available: it matches a permanent external reference. Otherwise keep the returned record ID and use the corresponding update operation for subsequent changes. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. Dictionary entries help meeting transcription recognize names and specialist terms. phrase is the spelling to keep; sounds_like supplies alternative pronunciations. Editing the dictionary does not rewrite previously saved transcripts. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [DictionaryEntryRecord](#dictionaryentryrecord-response-item) | Yes | The requested record, including its metadata and data fields. | ### DictionaryEntryRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:DictionaryEntry record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [DictionaryEntry](#dictionaryentry-response-item-data) | Yes | The record's fields. | ### DictionaryEntry · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `phrase` | string | Yes | Correct spelling of the name or term to recognize. | | `sounds_like` | array of string | No | Alternative phonetic spellings used to recognize the phrase in speech. | | `language` | string | No | Recognition language code, for example en for English or no for Norwegian. Omit when the term is not tied to a language. This field is an open string, not a closed enum. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List dictionary entries](/developers/reference/meetings/ListDictionaryEntries) - [Get dictionary entry](/developers/reference/meetings/GetDictionaryEntry) - [Upsert dictionary entry](/developers/reference/meetings/UpsertDictionaryEntry) - [Update dictionary entry](/developers/reference/meetings/UpdateDictionaryEntry) - [Delete dictionary entry](/developers/reference/meetings/DeleteDictionaryEntry) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.CreateDictionaryEntry' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "data": { "phrase": "Northstar", "sounds_like": [ "north star" ], "language": "en" } }' ``` #### TypeScript ```typescript 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.CreateDictionaryEntry", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "data": { "phrase": "Northstar", "sounds_like": [ "north star" ], "language": "en" } }), }); 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 = { "data": { "phrase": "Northstar", "sounds_like": [ "north star" ], "language": "en" } } request = Request( "https://api.brigg.app/v1/operations/meetings.CreateDictionaryEntry", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_dictionaryentry_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "phrase": "Northstar", "sounds_like": [ "north star" ], "language": "en" } } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "data": { "type": "object", "properties": { "phrase": { "type": "string", "description": "Correct spelling of the name or term to recognize." }, "sounds_like": { "type": "array", "items": { "type": "string" }, "description": "Alternative phonetic spellings used to recognize the phrase in speech." }, "language": { "type": "string", "description": "Recognition language code, for example en for English or no for Norwegian. Omit when the term is not tied to a language. This field is an open string, not a closed enum." } }, "required": [ "phrase" ], "additionalProperties": false, "description": "The record's fields.", "title": "DictionaryEntry" }, "private": { "type": "boolean", "description": "Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance." } }, "required": [ "data" ], "additionalProperties": false, "examples": [ { "data": { "phrase": "Northstar", "sounds_like": [ "north star" ], "language": "en" } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:DictionaryEntry record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "phrase": { "type": "string", "description": "Correct spelling of the name or term to recognize." }, "sounds_like": { "type": "array", "items": { "type": "string" }, "description": "Alternative phonetic spellings used to recognize the phrase in speech." }, "language": { "type": "string", "description": "Recognition language code, for example en for English or no for Norwegian. Omit when the term is not tied to a language. This field is an open string, not a closed enum." } }, "required": [ "phrase" ], "additionalProperties": false, "description": "The record's fields.", "title": "DictionaryEntry" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "DictionaryEntryRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_dictionaryentry_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "phrase": "Northstar", "sounds_like": [ "north star" ], "language": "en" } } } ] } ``` --- # Delete dictionary entry Delete a dictionary entry by ID. Repeating a deletion returns already_deleted. POST https://api.brigg.app/v1/operations/meetings.DeleteDictionaryEntry ## Access & visibility Allow `meetings.DeleteDictionaryEntry` on your API key. Resource read permissions: `core:DictionaryEntry`. Resource write permissions: `core:DictionaryEntry`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:DictionaryEntry` record. Use the relevant list operation to discover records. Use the record's top-level `id`, not a business field or account ID. | | `expected` | [object](#request-expected) | No | Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {"$absent":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource. | ### request.expected | Field | Type | Required | Description | | --- | --- | --- | --- | | `phrase` | string or [object](#request-expected-phrase) | No | Commit only if the previous phrase value matches; use $absent to require that this field is missing. | | `sounds_like` | array of string or [object](#request-expected-sounds-like) | No | Commit only if the previous sounds_like value matches; use $absent to require that this field is missing. | | `language` | string or [object](#request-expected-language) | No | Commit only if the previous language value matches; use $absent to require that this field is missing. | ### request.expected.phrase | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.sounds_like | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.language | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ## Deletion and retries A successful response reports whether this call removed the record or it was already absent. Check `cascaded` for dependent record IDs returned by the operation. Retrying the same action uses the original idempotency key. A successful deletion is not an archive you can restore through this operation. To avoid deleting a record someone has changed, read it first and put the relevant prior business values in `expected`. Keys are relative to `data`, not prefixed with `data.`. Use {"$absent": true} to require a missing field. A mismatch returns 409 conflict; read again and decide whether deletion is still appropriate. A revised action needs a new idempotency key. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `deleted` | string | Yes | deleted when this request removed the record; already_deleted when it was already absent. Allowed: `"deleted"`, `"already_deleted"`. | | `cascaded` | array of string | No | IDs of dependent records deleted with this 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `conflict` | A supplied expected value no longer matches. Read the record again before deciding whether to retry. | ## Next steps - [List dictionary entries](/developers/reference/meetings/ListDictionaryEntries) - [Get dictionary entry](/developers/reference/meetings/GetDictionaryEntry) - [Create dictionary entry](/developers/reference/meetings/CreateDictionaryEntry) - [Upsert dictionary entry](/developers/reference/meetings/UpsertDictionaryEntry) - [Update dictionary entry](/developers/reference/meetings/UpdateDictionaryEntry) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.DeleteDictionaryEntry' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_dictionaryentry_example" }' ``` #### TypeScript ```typescript 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.DeleteDictionaryEntry", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_dictionaryentry_example" }), }); 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_dictionaryentry_example" } request = Request( "https://api.brigg.app/v1/operations/meetings.DeleteDictionaryEntry", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "deleted": "deleted" } ``` ### Delete only if unchanged Use a value you actually read. A concurrent change refuses the write with 409 conflict. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.DeleteDictionaryEntry' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_dictionaryentry_example", "expected": { "phrase": "Northstar" } }' ``` #### TypeScript ```typescript 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.DeleteDictionaryEntry", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_dictionaryentry_example", "expected": { "phrase": "Northstar" } }), }); 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_dictionaryentry_example", "expected": { "phrase": "Northstar" } } request = Request( "https://api.brigg.app/v1/operations/meetings.DeleteDictionaryEntry", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "deleted": "deleted" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:DictionaryEntry` record. Use the relevant list operation to discover records. Use the record's top-level `id`, not a business field or account ID." }, "expected": { "type": "object", "description": "Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {\"$absent\":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource.", "additionalProperties": false, "properties": { "phrase": { "description": "Commit only if the previous phrase value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Correct spelling of the name or term to recognize." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "sounds_like": { "description": "Commit only if the previous sounds_like value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "type": "string" }, "description": "Alternative phonetic spellings used to recognize the phrase in speech." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "language": { "description": "Commit only if the previous language value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Recognition language code, for example en for English or no for Norwegian. Omit when the term is not tied to a language. This field is an open string, not a closed enum." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] } } } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_dictionaryentry_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "deleted": { "type": "string", "enum": [ "deleted", "already_deleted" ], "description": "deleted when this request removed the record; already_deleted when it was already absent." }, "cascaded": { "type": "array", "items": { "type": "string" }, "description": "IDs of dependent records deleted with this record." } }, "required": [ "deleted" ], "additionalProperties": false, "examples": [ { "deleted": "deleted" } ] } ``` --- # Update dictionary entry Update a dictionary entry by ID. Omitted fields stay unchanged; use unset to remove fields and expected to prevent overwriting a concurrent change. POST https://api.brigg.app/v1/operations/meetings.UpdateDictionaryEntry ## Access & visibility Allow `meetings.UpdateDictionaryEntry` on your API key. Resource read permissions: `core:DictionaryEntry`. Resource write permissions: `core:DictionaryEntry`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:DictionaryEntry` record. Use the relevant list operation to discover records. Use the record's top-level `id`, not a business field or account ID. | | `data` | [DictionaryEntry](#dictionaryentry-request-data) | No | The fields to set. | | `unset` | array of string | No | Keys of `data` to remove. Each item: `"phrase"`, `"sounds_like"`, `"language"`. | | `expected` | [object](#request-expected) | No | Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {"$absent":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource. | ### DictionaryEntry · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `phrase` | string | No | Correct spelling of the name or term to recognize. | | `sounds_like` | array of string | No | Alternative phonetic spellings used to recognize the phrase in speech. | | `language` | string | No | Recognition language code, for example en for English or no for Norwegian. Omit when the term is not tied to a language. This field is an open string, not a closed enum. | ### request.expected | Field | Type | Required | Description | | --- | --- | --- | --- | | `phrase` | string or [object](#request-expected-phrase) | No | Commit only if the previous phrase value matches; use $absent to require that this field is missing. | | `sounds_like` | array of string or [object](#request-expected-sounds-like) | No | Commit only if the previous sounds_like value matches; use $absent to require that this field is missing. | | `language` | string or [object](#request-expected-language) | No | Commit only if the previous language value matches; use $absent to require that this field is missing. | ### request.expected.phrase | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.sounds_like | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.language | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ## Update without losing changes Send only the business fields you want to change in `data`; omitted fields stay unchanged. Use `unset` to remove an optional field. Setting a field to null is a different action and is allowed only when its schema permits null. Use `expected` for a conditional update: supply the values you last read for the fields whose concurrent changes would matter. `{"$absent": true}` expects a missing field. A conflict means you must read the record again and decide how to reconcile the change. Keep the same idempotency key when retrying the original action; use a new key for a revised action. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. Dictionary entries help meeting transcription recognize names and specialist terms. phrase is the spelling to keep; sounds_like supplies alternative pronunciations. Editing the dictionary does not rewrite previously saved transcripts. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [DictionaryEntryRecord](#dictionaryentryrecord-response-item) | Yes | The requested record, including its metadata and data fields. | ### DictionaryEntryRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:DictionaryEntry record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [DictionaryEntry](#dictionaryentry-response-item-data) | Yes | The record's fields. | ### DictionaryEntry · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `phrase` | string | Yes | Correct spelling of the name or term to recognize. | | `sounds_like` | array of string | No | Alternative phonetic spellings used to recognize the phrase in speech. | | `language` | string | No | Recognition language code, for example en for English or no for Norwegian. Omit when the term is not tied to a language. This field is an open string, not a closed enum. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `conflict` | A supplied expected value no longer matches. Read the record again before deciding whether to retry. | ## Next steps - [List dictionary entries](/developers/reference/meetings/ListDictionaryEntries) - [Get dictionary entry](/developers/reference/meetings/GetDictionaryEntry) - [Create dictionary entry](/developers/reference/meetings/CreateDictionaryEntry) - [Upsert dictionary entry](/developers/reference/meetings/UpsertDictionaryEntry) - [Delete dictionary entry](/developers/reference/meetings/DeleteDictionaryEntry) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.UpdateDictionaryEntry' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_dictionaryentry_example", "data": { "sounds_like": [ "north star", "nort star" ] } }' ``` #### TypeScript ```typescript 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.UpdateDictionaryEntry", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_dictionaryentry_example", "data": { "sounds_like": [ "north star", "nort star" ] } }), }); 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_dictionaryentry_example", "data": { "sounds_like": [ "north star", "nort star" ] } } request = Request( "https://api.brigg.app/v1/operations/meetings.UpdateDictionaryEntry", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_dictionaryentry_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "phrase": "Northstar", "sounds_like": [ "north star", "nort star" ], "language": "en" } } } ``` ### Update only if unchanged Use a value you actually read. A concurrent change refuses the write with 409 conflict. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.UpdateDictionaryEntry' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_dictionaryentry_example", "data": { "sounds_like": [ "north star", "nort star" ] }, "expected": { "phrase": "Northstar" } }' ``` #### TypeScript ```typescript 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.UpdateDictionaryEntry", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_dictionaryentry_example", "data": { "sounds_like": [ "north star", "nort star" ] }, "expected": { "phrase": "Northstar" } }), }); 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_dictionaryentry_example", "data": { "sounds_like": [ "north star", "nort star" ] }, "expected": { "phrase": "Northstar" } } request = Request( "https://api.brigg.app/v1/operations/meetings.UpdateDictionaryEntry", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_dictionaryentry_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "phrase": "Northstar", "sounds_like": [ "north star", "nort star" ], "language": "en" } } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:DictionaryEntry` record. Use the relevant list operation to discover records. Use the record's top-level `id`, not a business field or account ID." }, "data": { "type": "object", "properties": { "phrase": { "type": "string", "description": "Correct spelling of the name or term to recognize." }, "sounds_like": { "type": "array", "items": { "type": "string" }, "description": "Alternative phonetic spellings used to recognize the phrase in speech." }, "language": { "type": "string", "description": "Recognition language code, for example en for English or no for Norwegian. Omit when the term is not tied to a language. This field is an open string, not a closed enum." } }, "required": [], "additionalProperties": false, "description": "The fields to set.", "title": "DictionaryEntry" }, "unset": { "type": "array", "items": { "type": "string", "enum": [ "phrase", "sounds_like", "language" ] }, "description": "Keys of `data` to remove." }, "expected": { "type": "object", "description": "Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {\"$absent\":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource.", "additionalProperties": false, "properties": { "phrase": { "description": "Commit only if the previous phrase value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Correct spelling of the name or term to recognize." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "sounds_like": { "description": "Commit only if the previous sounds_like value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "type": "string" }, "description": "Alternative phonetic spellings used to recognize the phrase in speech." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "language": { "description": "Commit only if the previous language value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Recognition language code, for example en for English or no for Norwegian. Omit when the term is not tied to a language. This field is an open string, not a closed enum." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] } } } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_dictionaryentry_example", "data": { "sounds_like": [ "north star", "nort star" ] } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:DictionaryEntry record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "phrase": { "type": "string", "description": "Correct spelling of the name or term to recognize." }, "sounds_like": { "type": "array", "items": { "type": "string" }, "description": "Alternative phonetic spellings used to recognize the phrase in speech." }, "language": { "type": "string", "description": "Recognition language code, for example en for English or no for Norwegian. Omit when the term is not tied to a language. This field is an open string, not a closed enum." } }, "required": [ "phrase" ], "additionalProperties": false, "description": "The record's fields.", "title": "DictionaryEntry" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "DictionaryEntryRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_dictionaryentry_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "phrase": "Northstar", "sounds_like": [ "north star", "nort star" ], "language": "en" } } } ] } ``` --- # Upsert dictionary entry Create or update a dictionary entry by a permanent external reference. Matching is exact within the workspace, resource type and ownership scope. Supplied fields replace their values; omitted fields stay unchanged. Deleted records are not recreated. POST https://api.brigg.app/v1/operations/meetings.UpsertDictionaryEntry ## Access & visibility Allow `meetings.UpsertDictionaryEntry` on your API key. Resource read permissions: `core:DictionaryEntry`. Resource write permissions: `core:DictionaryEntry`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `data` | [DictionaryEntry](#dictionaryentry-request-data) | Yes | The record's fields. | | `private` | boolean | No | Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance. | | `external_ref` | [object](#request-external-ref) | Yes | Permanent, case-sensitive source identity within this workspace, resource type and private/workspace scope. It is independent of API key rotation and retry receipt expiry. | ### DictionaryEntry · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `phrase` | string | Yes | Correct spelling of the name or term to recognize. | | `sounds_like` | array of string | No | Alternative phonetic spellings used to recognize the phrase in speech. | | `language` | string | No | Recognition language code, for example en for English or no for Norwegian. Omit when the term is not tied to a language. This field is an open string, not a closed enum. | ### request.external_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `namespace` | string | Yes | A stable name for the source system, such as crm-production. At least 1 character. | | `id` | string | Yes | The record ID in that source system. At least 1 character. | ## Sync with a permanent external reference Choose a stable `external_ref.namespace` for your source system and put its record ID in `external_ref.id`. Matching is case-sensitive and scoped to this workspace, resource type and private/workspace ownership. The reference survives API key replacement and the 30-day retry receipt window. It does not match records by email or name. Send the required create fields each time. A missing reference creates a record; an existing reference updates only supplied fields and preserves everything else. `created` tells you which happened. Use the same idempotency key when retrying a lost response and a new key for a later source change. Concurrent calls cannot create duplicate records. A deleted or inaccessible match is refused; the operation does not restore it or make a replacement. Use the returned `item.id` with the regular update operation when you need `unset` or a conditional `expected` edit. Changing `private` chooses a different ownership scope; it does not transfer an existing record. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. Dictionary entries help meeting transcription recognize names and specialist terms. phrase is the spelling to keep; sounds_like supplies alternative pronunciations. Editing the dictionary does not rewrite previously saved transcripts. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [DictionaryEntryRecord](#dictionaryentryrecord-response-item) | Yes | The requested record, including its metadata and data fields. | | `created` | boolean | Yes | True when this external reference created a record; false when it matched an existing record. | ### DictionaryEntryRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:DictionaryEntry record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [DictionaryEntry](#dictionaryentry-response-item-data) | Yes | The record's fields. | ### DictionaryEntry · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `phrase` | string | Yes | Correct spelling of the name or term to recognize. | | `sounds_like` | array of string | No | Alternative phonetic spellings used to recognize the phrase in speech. | | `language` | string | No | Recognition language code, for example en for English or no for Norwegian. Omit when the term is not tied to a language. This field is an open string, not a closed enum. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List dictionary entries](/developers/reference/meetings/ListDictionaryEntries) - [Get dictionary entry](/developers/reference/meetings/GetDictionaryEntry) - [Create dictionary entry](/developers/reference/meetings/CreateDictionaryEntry) - [Update dictionary entry](/developers/reference/meetings/UpdateDictionaryEntry) - [Delete dictionary entry](/developers/reference/meetings/DeleteDictionaryEntry) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### First sync Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.UpsertDictionaryEntry' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "phrase": "Northstar", "sounds_like": [ "north star" ], "language": "en" } }' ``` #### TypeScript ```typescript 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.UpsertDictionaryEntry", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "phrase": "Northstar", "sounds_like": [ "north star" ], "language": "en" } }), }); 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 = { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "phrase": "Northstar", "sounds_like": [ "north star" ], "language": "en" } } request = Request( "https://api.brigg.app/v1/operations/meetings.UpsertDictionaryEntry", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_dictionaryentry_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "phrase": "Northstar", "sounds_like": [ "north star" ], "language": "en" } }, "created": true } ``` ### Later sync The same external reference returns the same record ID. Use a new idempotency key for a later source change. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.UpsertDictionaryEntry' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "phrase": "Northstar", "sounds_like": [ "north star" ], "language": "en" } }' ``` #### TypeScript ```typescript 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.UpsertDictionaryEntry", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "phrase": "Northstar", "sounds_like": [ "north star" ], "language": "en" } }), }); 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 = { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "phrase": "Northstar", "sounds_like": [ "north star" ], "language": "en" } } request = Request( "https://api.brigg.app/v1/operations/meetings.UpsertDictionaryEntry", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_dictionaryentry_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "phrase": "Northstar", "sounds_like": [ "north star" ], "language": "en" } }, "created": false } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "data": { "type": "object", "properties": { "phrase": { "type": "string", "description": "Correct spelling of the name or term to recognize." }, "sounds_like": { "type": "array", "items": { "type": "string" }, "description": "Alternative phonetic spellings used to recognize the phrase in speech." }, "language": { "type": "string", "description": "Recognition language code, for example en for English or no for Norwegian. Omit when the term is not tied to a language. This field is an open string, not a closed enum." } }, "required": [ "phrase" ], "additionalProperties": false, "description": "The record's fields.", "title": "DictionaryEntry" }, "private": { "type": "boolean", "description": "Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance." }, "external_ref": { "type": "object", "description": "Permanent, case-sensitive source identity within this workspace, resource type and private/workspace scope. It is independent of API key rotation and retry receipt expiry.", "properties": { "namespace": { "type": "string", "minLength": 1, "description": "A stable name for the source system, such as crm-production." }, "id": { "type": "string", "minLength": 1, "description": "The record ID in that source system." } }, "required": [ "namespace", "id" ], "additionalProperties": false } }, "required": [ "external_ref", "data" ], "additionalProperties": false, "examples": [ { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "phrase": "Northstar", "sounds_like": [ "north star" ], "language": "en" } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:DictionaryEntry record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "phrase": { "type": "string", "description": "Correct spelling of the name or term to recognize." }, "sounds_like": { "type": "array", "items": { "type": "string" }, "description": "Alternative phonetic spellings used to recognize the phrase in speech." }, "language": { "type": "string", "description": "Recognition language code, for example en for English or no for Norwegian. Omit when the term is not tied to a language. This field is an open string, not a closed enum." } }, "required": [ "phrase" ], "additionalProperties": false, "description": "The record's fields.", "title": "DictionaryEntry" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "DictionaryEntryRecord" }, "created": { "type": "boolean", "description": "True when this external reference created a record; false when it matched an existing record." } }, "required": [ "item", "created" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_dictionaryentry_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "phrase": "Northstar", "sounds_like": [ "north star" ], "language": "en" } }, "created": true } ] } ``` --- # Get meeting Read a meeting by ID. Returns item: null when no visible record matches. POST https://api.brigg.app/v1/operations/meetings.GetMeeting ## Access & visibility Allow `meetings.GetMeeting` on your API key. Resource read permissions: `core:Meeting`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:Meeting` record. Find it with [meetings.ListMeetings](/developers/reference/meetings/ListMeetings). Use the record's top-level `id`, not a business field or account ID. | ## Response Returns **200 OK** with a JSON body. `item: null` means there is no matching record visible to this caller. It does not reveal whether an inaccessible record exists. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. An ended meeting is not necessarily summarized yet. Summary fields can be absent while work is pending or when no summary is available; this response does not expose the reason. Transcript text and recording URLs are not part of this model. Personal notes are a separate resource and retain the acting member's access rules. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [MeetingRecord](#meetingrecord-response-item) or null | Yes | null when no such record | ### MeetingRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Meeting record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Meeting](#meeting-response-item-data) | Yes | The record's fields. | ### Meeting · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string | No | Meeting title. May be absent when no title has been supplied. | | `started_by` | string | No | Host account ID. This is the member identity that owns the meeting; created_by is separate record provenance. | | `start_time` | number | Yes | Meeting start time in Unix milliseconds. Use a number, not an ISO date string, when filtering this field. | | `end_time` | number | No | Meeting end time in Unix milliseconds. May be absent before the meeting ends. | | `status` | string | Yes | Meeting lifecycle state, including live, paused and ended. This is an open string, not a closed enum; tolerate additional states. | | `language` | string | No | Language recorded for the meeting, such as en or no. It may differ from summary_language. | | `participants` | array of string or [MeetingParticipant](#meetingparticipant-response-item-data-participants) | No | Attendee names or objects containing a name, email and optional Person record reference. | | `calendar_event_id` | string | No | ID of a `core:CalendarEvent` record. Find it with [meetings.ListCalendarEvents](/developers/reference/meetings/ListCalendarEvents) and use the top-level `id`. This is not an account ID or a display name. | | `sharing_external` | boolean | No | Whether external attendees were identified when the meeting was prepared. This is not permission to share the meeting externally; absence means this fact was not recorded. | | `call_direction` | string | No | Phone call direction, currently inbound or outbound. Absent for meetings without phone-call metadata. | | `call_outcome` | string | No | How a phone call ended, including completed, no_answer, busy, declined, canceled or failed. This is an open string. | | `call_duration_ms` | number | No | Recorded phone-call duration in milliseconds. | | `counterpart_e164` | string | No | Other party's phone number in international E.164 format, such as +4721001234. | | `call_forwarded` | boolean | No | Whether the incoming call was forwarded from another phone number. | | `conference_url` | string | No | Conference link from the calendar invitation, when one is available. | | `contact_refs` | array of string | No | Linked Person record IDs. Use has to filter for a particular contact. | | `company_refs` | array of string | No | Linked Company record IDs. Use has to filter for a particular company. | | `related_meetings` | array of string | No | IDs of related Meeting records. Each related record has its own access rules. | | `agenda` | array of [object](#response-item-data-agenda) | No | Two-level agenda: topics and optional subtopics. Status tracks how much of each topic was covered. | | `meeting_type` | string | No | Descriptive meeting category in the meeting's language. Free text, not a fixed enum. | | `gist` | string | No | One- or two-line takeaway from the meeting. | | `summary_bullets` | array of string | No | Key points extracted from the meeting. | | `summary` | string | No | Full meeting summary formatted as Markdown. | | `summary_language` | string | No | Language of the generated summary, such as en or no. | | `custom_summary` | [object](#response-item-data-custom-summary) | No | Instructions and optional example used to generate a custom summary. This is configuration, not the generated summary. | ### MeetingParticipant · response.item.data.participants[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | No | Display name. | | `email` | string | No | Email address. | | `ref` | string | No | Person record ID for this attendee, when matched to a customer contact. It is not a workspace account ID. | ### response.item.data.agenda[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | | `subtopics` | array of [object](#response-item-data-agenda-subtopics) | No | Second-level discussion topics; no deeper nesting is supported. | ### response.item.data.agenda[].subtopics[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | ### response.item.data.custom_summary | Field | Type | Required | Description | | --- | --- | --- | --- | | `example` | string | No | Example output illustrating the desired summary style. | | `instructions` | string | No | Instructions to follow when generating the summary. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [List meetings](/developers/reference/meetings/ListMeetings) - [Create meeting](/developers/reference/meetings/CreateMeeting) - [Upsert meeting](/developers/reference/meetings/UpsertMeeting) - [Update meeting](/developers/reference/meetings/UpdateMeeting) - [Delete meeting](/developers/reference/meetings/DeleteMeeting) - [Read personal meeting notes](/developers/reference/meetings/ListMeetingNotes) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.GetMeeting' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "e_meeting_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/meetings.GetMeeting", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "id": "e_meeting_example" }), }); 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 payload = { "id": "e_meeting_example" } request = Request( "https://api.brigg.app/v1/operations/meetings.GetMeeting", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "item": { "id": "e_meeting_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "title": "Northstar · project kickoff", "start_time": 1791277200000, "end_time": 1791279900000, "status": "ended", "started_by": "a_jamie", "participants": [ { "name": "Jamie Lee", "email": "jamie@example.com" }, { "name": "Alex Morgan", "email": "alex@example.org", "ref": "e_person_alex" } ], "company_refs": [ "e_company_northstar" ], "gist": "The team agreed to begin the pilot on 19 October.", "summary_bullets": [ "Alex will send the source data by Friday.", "Jamie will prepare the pilot workspace." ], "summary": "## Decisions\nStart the pilot on 19 October.\n\n## Next steps\n- Alex: send source data by Friday.\n- Jamie: prepare the workspace.", "summary_language": "en" } } } ``` ### No visible record A missing or inaccessible record returns item: null. Do not treat this as proof that a record exists for another member. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.GetMeeting' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "e_meeting_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/meetings.GetMeeting", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "id": "e_meeting_example" }), }); 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 payload = { "id": "e_meeting_example" } request = Request( "https://api.brigg.app/v1/operations/meetings.GetMeeting", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "item": null } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:Meeting` record. Find it with [meetings.ListMeetings](/developers/reference/meetings/ListMeetings). Use the record's top-level `id`, not a business field or account ID." } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_meeting_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": [ "object", "null" ], "properties": { "id": { "type": "string", "description": "Stable core:Meeting record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "title": { "type": "string", "description": "Meeting title. May be absent when no title has been supplied." }, "started_by": { "type": "string", "description": "Host account ID. This is the member identity that owns the meeting; created_by is separate record provenance." }, "start_time": { "type": "number", "description": "Meeting start time in Unix milliseconds. Use a number, not an ISO date string, when filtering this field." }, "end_time": { "type": "number", "description": "Meeting end time in Unix milliseconds. May be absent before the meeting ends." }, "status": { "type": "string", "description": "Meeting lifecycle state, including live, paused and ended. This is an open string, not a closed enum; tolerate additional states." }, "language": { "type": "string", "description": "Language recorded for the meeting, such as en or no. It may differ from summary_language." }, "participants": { "type": "array", "items": { "title": "MeetingParticipant", "anyOf": [ { "type": "string", "title": "MeetingParticipant" }, { "type": "object", "properties": { "name": { "type": "string", "description": "Display name." }, "email": { "type": "string", "description": "Email address." }, "ref": { "type": "string", "description": "Person record ID for this attendee, when matched to a customer contact. It is not a workspace account ID." } }, "required": [], "additionalProperties": false, "title": "MeetingParticipant" } ] }, "description": "Attendee names or objects containing a name, email and optional Person record reference." }, "calendar_event_id": { "type": "string", "description": "ID of a `core:CalendarEvent` record. Find it with [meetings.ListCalendarEvents](/developers/reference/meetings/ListCalendarEvents) and use the top-level `id`. This is not an account ID or a display name." }, "sharing_external": { "type": "boolean", "description": "Whether external attendees were identified when the meeting was prepared. This is not permission to share the meeting externally; absence means this fact was not recorded." }, "call_direction": { "type": "string", "description": "Phone call direction, currently inbound or outbound. Absent for meetings without phone-call metadata." }, "call_outcome": { "type": "string", "description": "How a phone call ended, including completed, no_answer, busy, declined, canceled or failed. This is an open string." }, "call_duration_ms": { "type": "number", "description": "Recorded phone-call duration in milliseconds." }, "counterpart_e164": { "type": "string", "description": "Other party's phone number in international E.164 format, such as +4721001234." }, "call_forwarded": { "type": "boolean", "description": "Whether the incoming call was forwarded from another phone number." }, "conference_url": { "type": "string", "description": "Conference link from the calendar invitation, when one is available." }, "contact_refs": { "type": "array", "items": { "type": "string", "description": "id of a core:Person" }, "description": "Linked Person record IDs. Use has to filter for a particular contact." }, "company_refs": { "type": "array", "items": { "type": "string", "description": "id of a core:Company" }, "description": "Linked Company record IDs. Use has to filter for a particular company." }, "related_meetings": { "type": "array", "items": { "type": "string", "description": "id of a core:Meeting" }, "description": "IDs of related Meeting records. Each related record has its own access rules." }, "agenda": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." }, "subtopics": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." } }, "additionalProperties": false }, "description": "Second-level discussion topics; no deeper nesting is supported." } }, "additionalProperties": false }, "description": "Two-level agenda: topics and optional subtopics. Status tracks how much of each topic was covered." }, "meeting_type": { "type": "string", "description": "Descriptive meeting category in the meeting's language. Free text, not a fixed enum." }, "gist": { "type": "string", "description": "One- or two-line takeaway from the meeting." }, "summary_bullets": { "type": "array", "items": { "type": "string" }, "description": "Key points extracted from the meeting." }, "summary": { "type": "string", "description": "Full meeting summary formatted as Markdown." }, "summary_language": { "type": "string", "description": "Language of the generated summary, such as en or no." }, "custom_summary": { "type": "object", "properties": { "example": { "type": "string", "description": "Example output illustrating the desired summary style." }, "instructions": { "type": "string", "description": "Instructions to follow when generating the summary." } }, "additionalProperties": false, "description": "Instructions and optional example used to generate a custom summary. This is configuration, not the generated summary." } }, "required": [ "start_time", "status" ], "additionalProperties": false, "description": "The record's fields.", "title": "Meeting" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "null when no such record", "title": "MeetingRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_meeting_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "title": "Northstar · project kickoff", "start_time": 1791277200000, "end_time": 1791279900000, "status": "ended", "started_by": "a_jamie", "participants": [ { "name": "Jamie Lee", "email": "jamie@example.com" }, { "name": "Alex Morgan", "email": "alex@example.org", "ref": "e_person_alex" } ], "company_refs": [ "e_company_northstar" ], "gist": "The team agreed to begin the pilot on 19 October.", "summary_bullets": [ "Alex will send the source data by Friday.", "Jamie will prepare the pilot workspace." ], "summary": "## Decisions\nStart the pilot on 19 October.\n\n## Next steps\n- Alex: send source data by Friday.\n- Jamie: prepare the workspace.", "summary_language": "en" } } } ] } ``` --- # Get recently ended meeting Find your most recently ended hosted meeting from the last five minutes. Returns meeting_id: null when none qualifies. POST https://api.brigg.app/v1/operations/meetings.GetRecentlyEndedMeeting ## Access & visibility Allow `meetings.GetRecentlyEndedMeeting` on your API key. Resource read permissions: `core:Meeting`. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/permissions) ## Request No parameters. Send an empty JSON object (`{}`). ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `meeting_id` | string or null | Yes | Meeting identifier. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 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. | ## Next steps [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.GetRecentlyEndedMeeting' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Brigg-Act-As: $BRIGG_ACT_AS" \ --data-raw '{}' ``` #### 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 response = await fetch("https://api.brigg.app/v1/operations/meetings.GetRecentlyEndedMeeting", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Brigg-Act-As": actAs, }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/meetings.GetRecentlyEndedMeeting", 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"], }, 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 { "meeting_id": "e_meeting_kickoff" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": {}, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "meeting_id": { "type": [ "string", "null" ], "description": "Meeting identifier." } }, "required": [ "meeting_id" ], "additionalProperties": false, "examples": [ { "meeting_id": "e_meeting_kickoff" } ] } ``` --- # List meetings List meetings visible to the credential, with filtering, sorting and cursor pagination. POST https://api.brigg.app/v1/operations/meetings.ListMeetings ## Access & visibility Allow `meetings.ListMeetings` on your API key. Resource read permissions: `core:Meeting`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `filters` | array of [object](#request-filters) | No | Conditions the row must ALL satisfy. | | `sort` | [object](#request-sort) | No | Sort order for the results. Defaults to updated_at descending, with id as a tie-breaker. | | `limit` | integer | No | Maximum number of results to return in this page. Continue with next_cursor when returned. Default: `100`. Minimum: 1. | | `cursor` | string | No | The `next_cursor` of the previous page. | ### request.filters[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | `data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private. Allowed: `"id"`, `"created_at"`, `"updated_at"`, `"created_by"`, `"private"`, `"data.title"`, `"data.started_by"`, `"data.start_time"`, `"data.end_time"`, `"data.status"`, `"data.language"`, `"data.participants"`, `"data.calendar_event_id"`, `"data.sharing_external"`, `"data.call_direction"`, `"data.call_outcome"`, `"data.call_duration_ms"`, `"data.counterpart_e164"`, `"data.call_forwarded"`, `"data.conference_url"`, `"data.contact_refs"`, `"data.company_refs"`, `"data.related_meetings"`, `"data.agenda"`, `"data.meeting_type"`, `"data.gist"`, `"data.summary_bullets"`, `"data.summary"`, `"data.summary_language"`, `"data.custom_summary"`. | | `op` | string | Yes | Comparison operator. Use in with an array, or omit value for is_empty and is_not_empty. Allowed: `"eq"`, `"neq"`, `"contains"`, `"starts_with"`, `"gt"`, `"gte"`, `"lt"`, `"lte"`, `"in"`, `"has"`, `"is_empty"`, `"is_not_empty"`. | | `value` | JSON value | No | The comparison value; an array for `in`; omitted for is_empty / is_not_empty. | ### request.sort | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | `data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private. Allowed: `"id"`, `"created_at"`, `"updated_at"`, `"created_by"`, `"private"`, `"data.title"`, `"data.started_by"`, `"data.start_time"`, `"data.end_time"`, `"data.status"`, `"data.language"`, `"data.participants"`, `"data.calendar_event_id"`, `"data.sharing_external"`, `"data.call_direction"`, `"data.call_outcome"`, `"data.call_duration_ms"`, `"data.counterpart_e164"`, `"data.call_forwarded"`, `"data.conference_url"`, `"data.contact_refs"`, `"data.company_refs"`, `"data.related_meetings"`, `"data.agenda"`, `"data.meeting_type"`, `"data.gist"`, `"data.summary_bullets"`, `"data.summary"`, `"data.summary_language"`, `"data.custom_summary"`. | | `direction` | string | No | Sort direction: asc for ascending or desc for descending. Allowed: `"asc"`, `"desc"`. | ## Filtering and sorting All conditions are combined with **AND**. Address business fields as `data.`, and record metadata as `id`, `created_at`, `updated_at`, `created_by` or `private`. A field path names one field; it does not traverse nested objects. | Operator | Meaning | Value | | --- | --- | --- | | `eq` | Equal to a scalar | String, number, boolean or null | | `neq` | Not equal; missing values also match | String, number, boolean or null | | `contains` | Case-insensitive text contains | String; % and _ are literal characters | | `starts_with` | Case-insensitive text prefix | String | | `gt`, `gte` | Greater than / at least | Number or string appropriate to the field | | `lt`, `lte` | Less than / at most | Number or string appropriate to the field | | `in` | Equal to any supplied scalar | Nonempty array of strings, numbers, booleans or null | | `has` | Array contains a string | One string; does not match properties inside array objects | | `is_empty` | Missing, null, empty string or empty array | Omit value | | `is_not_empty` | Has a nonempty value | Omit value | Match the stored field's type. Numeric business timestamps take Unix milliseconds; date-only business fields take `YYYY-MM-DD`. The record metadata fields `created_at` and `updated_at` also accept ISO timestamps for ordered comparisons. Sorting defaults to `updated_at` descending. If you supply `sort.field` without `sort.direction`, direction is `desc`. The record ID breaks ties; missing values sort last. ## Response Returns **200 OK** with a JSON body. An empty `items` array means this page contains no matching visible results. Follow `next_cursor` when present. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. An ended meeting is not necessarily summarized yet. Summary fields can be absent while work is pending or when no summary is available; this response does not expose the reason. Transcript text and recording URLs are not part of this model. Personal notes are a separate resource and retain the acting member's access rules. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [MeetingRecord](#meetingrecord-response-items) | Yes | Records visible under the credential's grants and the selected data scope, matching the requested filters. Pass next_cursor as cursor to continue when a next cursor is returned. | | `next_cursor` | string | No | Pass this value as cursor to continue with the same filters, sort and credential. Omitted when there are no more results. | ### MeetingRecord · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Meeting record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Meeting](#meeting-response-items-data) | Yes | The record's fields. | ### Meeting · response.items[].data | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string | No | Meeting title. May be absent when no title has been supplied. | | `started_by` | string | No | Host account ID. This is the member identity that owns the meeting; created_by is separate record provenance. | | `start_time` | number | Yes | Meeting start time in Unix milliseconds. Use a number, not an ISO date string, when filtering this field. | | `end_time` | number | No | Meeting end time in Unix milliseconds. May be absent before the meeting ends. | | `status` | string | Yes | Meeting lifecycle state, including live, paused and ended. This is an open string, not a closed enum; tolerate additional states. | | `language` | string | No | Language recorded for the meeting, such as en or no. It may differ from summary_language. | | `participants` | array of string or [MeetingParticipant](#meetingparticipant-response-items-data-participants) | No | Attendee names or objects containing a name, email and optional Person record reference. | | `calendar_event_id` | string | No | ID of a `core:CalendarEvent` record. Find it with [meetings.ListCalendarEvents](/developers/reference/meetings/ListCalendarEvents) and use the top-level `id`. This is not an account ID or a display name. | | `sharing_external` | boolean | No | Whether external attendees were identified when the meeting was prepared. This is not permission to share the meeting externally; absence means this fact was not recorded. | | `call_direction` | string | No | Phone call direction, currently inbound or outbound. Absent for meetings without phone-call metadata. | | `call_outcome` | string | No | How a phone call ended, including completed, no_answer, busy, declined, canceled or failed. This is an open string. | | `call_duration_ms` | number | No | Recorded phone-call duration in milliseconds. | | `counterpart_e164` | string | No | Other party's phone number in international E.164 format, such as +4721001234. | | `call_forwarded` | boolean | No | Whether the incoming call was forwarded from another phone number. | | `conference_url` | string | No | Conference link from the calendar invitation, when one is available. | | `contact_refs` | array of string | No | Linked Person record IDs. Use has to filter for a particular contact. | | `company_refs` | array of string | No | Linked Company record IDs. Use has to filter for a particular company. | | `related_meetings` | array of string | No | IDs of related Meeting records. Each related record has its own access rules. | | `agenda` | array of [object](#response-items-data-agenda) | No | Two-level agenda: topics and optional subtopics. Status tracks how much of each topic was covered. | | `meeting_type` | string | No | Descriptive meeting category in the meeting's language. Free text, not a fixed enum. | | `gist` | string | No | One- or two-line takeaway from the meeting. | | `summary_bullets` | array of string | No | Key points extracted from the meeting. | | `summary` | string | No | Full meeting summary formatted as Markdown. | | `summary_language` | string | No | Language of the generated summary, such as en or no. | | `custom_summary` | [object](#response-items-data-custom-summary) | No | Instructions and optional example used to generate a custom summary. This is configuration, not the generated summary. | ### MeetingParticipant · response.items[].data.participants[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | No | Display name. | | `email` | string | No | Email address. | | `ref` | string | No | Person record ID for this attendee, when matched to a customer contact. It is not a workspace account ID. | ### response.items[].data.agenda[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | | `subtopics` | array of [object](#response-items-data-agenda-subtopics) | No | Second-level discussion topics; no deeper nesting is supported. | ### response.items[].data.agenda[].subtopics[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | ### response.items[].data.custom_summary | Field | Type | Required | Description | | --- | --- | --- | --- | | `example` | string | No | Example output illustrating the desired summary style. | | `instructions` | string | No | Instructions to follow when generating the summary. | ## Pagination Pass `next_cursor` from the response as `cursor` on the next request. Keep the same filters, sort and acting identity. Stop when `next_cursor` is absent; do not infer completion from the number of items. The default page size is **100**; `limit` must be a positive integer. **Pagination is a live view, not a snapshot.** Changes between pages can move records across page boundaries. Upsert by record ID rather than appending blindly. For recurring synchronization, use an overlapping update window and deduplicate records. Periodically reconcile IDs to detect deletions. [Resource webhooks](/developers/webhooks) can supplement synchronization for eligible workspace-shared records only: they do not export private or project-scoped records. Personal data still needs polling and reconciliation. ```typescript const query = { "sort": { "field": "data.start_time", "direction": "desc" }, "limit": 50 }; let cursor; do { const response = await fetch("https://api.brigg.app/v1/operations/meetings.ListMeetings", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ ...query, ...(cursor ? { cursor } : {}) }), }); const page = await response.json(); if (!response.ok) throw new Error(`${response.status}: ${page.message}`); for (const item of page.items) { console.log(item); // Process or upsert each result. } cursor = page.next_cursor; } while (cursor); ``` ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | | 400 | `cursor_invalid` | Restart pagination with no cursor. | | 400 | `cursor_mismatch` | Use the cursor with the original filters, sort order and credential. | ## Next steps - [Get meeting](/developers/reference/meetings/GetMeeting) - [Create meeting](/developers/reference/meetings/CreateMeeting) - [Upsert meeting](/developers/reference/meetings/UpsertMeeting) - [Update meeting](/developers/reference/meetings/UpdateMeeting) - [Delete meeting](/developers/reference/meetings/DeleteMeeting) - [Read personal meeting notes](/developers/reference/meetings/ListMeetingNotes) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Recent meetings Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.ListMeetings' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "sort": { "field": "data.start_time", "direction": "desc" }, "limit": 50 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/meetings.ListMeetings", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "sort": { "field": "data.start_time", "direction": "desc" }, "limit": 50 }), }); 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 payload = { "sort": { "field": "data.start_time", "direction": "desc" }, "limit": 50 } request = Request( "https://api.brigg.app/v1/operations/meetings.ListMeetings", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_meeting_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "title": "Northstar · project kickoff", "start_time": 1791277200000, "end_time": 1791279900000, "status": "ended", "started_by": "a_jamie", "participants": [ { "name": "Jamie Lee", "email": "jamie@example.com" }, { "name": "Alex Morgan", "email": "alex@example.org", "ref": "e_person_alex" } ], "company_refs": [ "e_company_northstar" ], "gist": "The team agreed to begin the pilot on 19 October.", "summary_bullets": [ "Alex will send the source data by Friday.", "Jamie will prepare the pilot workspace." ], "summary": "## Decisions\nStart the pilot on 19 October.\n\n## Next steps\n- Alex: send source data by Friday.\n- Jamie: prepare the workspace.", "summary_language": "en" } } ] } ``` ### Ended meetings in a date range 1 October 2026 inclusive to 1 November 2026 exclusive, in UTC. start_time uses Unix milliseconds. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.ListMeetings' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "filters": [ { "field": "data.status", "op": "eq", "value": "ended" }, { "field": "data.start_time", "op": "gte", "value": 1790812800000 }, { "field": "data.start_time", "op": "lt", "value": 1793491200000 } ], "sort": { "field": "data.start_time", "direction": "asc" }, "limit": 50 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/meetings.ListMeetings", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "filters": [ { "field": "data.status", "op": "eq", "value": "ended" }, { "field": "data.start_time", "op": "gte", "value": 1790812800000 }, { "field": "data.start_time", "op": "lt", "value": 1793491200000 } ], "sort": { "field": "data.start_time", "direction": "asc" }, "limit": 50 }), }); 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 payload = { "filters": [ { "field": "data.status", "op": "eq", "value": "ended" }, { "field": "data.start_time", "op": "gte", "value": 1790812800000 }, { "field": "data.start_time", "op": "lt", "value": 1793491200000 } ], "sort": { "field": "data.start_time", "direction": "asc" }, "limit": 50 } request = Request( "https://api.brigg.app/v1/operations/meetings.ListMeetings", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_meeting_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "title": "Northstar · project kickoff", "start_time": 1791277200000, "end_time": 1791279900000, "status": "ended", "started_by": "a_jamie", "participants": [ { "name": "Jamie Lee", "email": "jamie@example.com" }, { "name": "Alex Morgan", "email": "alex@example.org", "ref": "e_person_alex" } ], "company_refs": [ "e_company_northstar" ], "gist": "The team agreed to begin the pilot on 19 October.", "summary_bullets": [ "Alex will send the source data by Friday.", "Jamie will prepare the pilot workspace." ], "summary": "## Decisions\nStart the pilot on 19 October.\n\n## Next steps\n- Alex: send source data by Friday.\n- Jamie: prepare the workspace.", "summary_language": "en" } } ] } ``` ### Meetings for one company Use has to match an ID in company_refs. The ID is a Company record, not the workspace ID. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.ListMeetings' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "filters": [ { "field": "data.company_refs", "op": "has", "value": "e_company_northstar" } ], "sort": { "field": "data.start_time", "direction": "desc" }, "limit": 50 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/meetings.ListMeetings", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "filters": [ { "field": "data.company_refs", "op": "has", "value": "e_company_northstar" } ], "sort": { "field": "data.start_time", "direction": "desc" }, "limit": 50 }), }); 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 payload = { "filters": [ { "field": "data.company_refs", "op": "has", "value": "e_company_northstar" } ], "sort": { "field": "data.start_time", "direction": "desc" }, "limit": 50 } request = Request( "https://api.brigg.app/v1/operations/meetings.ListMeetings", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_meeting_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "title": "Northstar · project kickoff", "start_time": 1791277200000, "end_time": 1791279900000, "status": "ended", "started_by": "a_jamie", "participants": [ { "name": "Jamie Lee", "email": "jamie@example.com" }, { "name": "Alex Morgan", "email": "alex@example.org", "ref": "e_person_alex" } ], "company_refs": [ "e_company_northstar" ], "gist": "The team agreed to begin the pilot on 19 October.", "summary_bullets": [ "Alex will send the source data by Friday.", "Jamie will prepare the pilot workspace." ], "summary": "## Decisions\nStart the pilot on 19 October.\n\n## Next steps\n- Alex: send source data by Friday.\n- Jamie: prepare the workspace.", "summary_language": "en" } } ] } ``` ### Records updated since a checkpoint 6 October 2026 at 00:00 UTC. Use an overlap window and upsert by ID when synchronizing. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.ListMeetings' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/meetings.ListMeetings", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 }), }); 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 payload = { "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 } request = Request( "https://api.brigg.app/v1/operations/meetings.ListMeetings", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_meeting_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "title": "Northstar · project kickoff", "start_time": 1791277200000, "end_time": 1791279900000, "status": "ended", "started_by": "a_jamie", "participants": [ { "name": "Jamie Lee", "email": "jamie@example.com" }, { "name": "Alex Morgan", "email": "alex@example.org", "ref": "e_person_alex" } ], "company_refs": [ "e_company_northstar" ], "gist": "The team agreed to begin the pilot on 19 October.", "summary_bullets": [ "Alex will send the source data by Friday.", "Jamie will prepare the pilot workspace." ], "summary": "## Decisions\nStart the pilot on 19 October.\n\n## Next steps\n- Alex: send source data by Friday.\n- Jamie: prepare the workspace.", "summary_language": "en" } } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "filters": { "type": "array", "items": { "type": "object", "properties": { "field": { "type": "string", "description": "`data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private.", "enum": [ "id", "created_at", "updated_at", "created_by", "private", "data.title", "data.started_by", "data.start_time", "data.end_time", "data.status", "data.language", "data.participants", "data.calendar_event_id", "data.sharing_external", "data.call_direction", "data.call_outcome", "data.call_duration_ms", "data.counterpart_e164", "data.call_forwarded", "data.conference_url", "data.contact_refs", "data.company_refs", "data.related_meetings", "data.agenda", "data.meeting_type", "data.gist", "data.summary_bullets", "data.summary", "data.summary_language", "data.custom_summary" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "contains", "starts_with", "gt", "gte", "lt", "lte", "in", "has", "is_empty", "is_not_empty" ], "description": "Comparison operator. Use in with an array, or omit value for is_empty and is_not_empty." }, "value": { "description": "The comparison value; an array for `in`; omitted for is_empty / is_not_empty." } }, "required": [ "field", "op" ], "additionalProperties": false }, "description": "Conditions the row must ALL satisfy." }, "sort": { "type": "object", "properties": { "field": { "type": "string", "description": "`data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private.", "enum": [ "id", "created_at", "updated_at", "created_by", "private", "data.title", "data.started_by", "data.start_time", "data.end_time", "data.status", "data.language", "data.participants", "data.calendar_event_id", "data.sharing_external", "data.call_direction", "data.call_outcome", "data.call_duration_ms", "data.counterpart_e164", "data.call_forwarded", "data.conference_url", "data.contact_refs", "data.company_refs", "data.related_meetings", "data.agenda", "data.meeting_type", "data.gist", "data.summary_bullets", "data.summary", "data.summary_language", "data.custom_summary" ] }, "direction": { "type": "string", "enum": [ "asc", "desc" ], "description": "Sort direction: asc for ascending or desc for descending." } }, "required": [ "field" ], "additionalProperties": false, "description": "Sort order for the results. Defaults to updated_at descending, with id as a tie-breaker." }, "limit": { "type": "integer", "minimum": 1, "default": 100, "description": "Maximum number of results to return in this page. Continue with next_cursor when returned." }, "cursor": { "type": "string", "description": "The `next_cursor` of the previous page." } }, "additionalProperties": false, "examples": [ { "sort": { "field": "data.start_time", "direction": "desc" }, "limit": 50 } ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:Meeting record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "title": { "type": "string", "description": "Meeting title. May be absent when no title has been supplied." }, "started_by": { "type": "string", "description": "Host account ID. This is the member identity that owns the meeting; created_by is separate record provenance." }, "start_time": { "type": "number", "description": "Meeting start time in Unix milliseconds. Use a number, not an ISO date string, when filtering this field." }, "end_time": { "type": "number", "description": "Meeting end time in Unix milliseconds. May be absent before the meeting ends." }, "status": { "type": "string", "description": "Meeting lifecycle state, including live, paused and ended. This is an open string, not a closed enum; tolerate additional states." }, "language": { "type": "string", "description": "Language recorded for the meeting, such as en or no. It may differ from summary_language." }, "participants": { "type": "array", "items": { "title": "MeetingParticipant", "anyOf": [ { "type": "string", "title": "MeetingParticipant" }, { "type": "object", "properties": { "name": { "type": "string", "description": "Display name." }, "email": { "type": "string", "description": "Email address." }, "ref": { "type": "string", "description": "Person record ID for this attendee, when matched to a customer contact. It is not a workspace account ID." } }, "required": [], "additionalProperties": false, "title": "MeetingParticipant" } ] }, "description": "Attendee names or objects containing a name, email and optional Person record reference." }, "calendar_event_id": { "type": "string", "description": "ID of a `core:CalendarEvent` record. Find it with [meetings.ListCalendarEvents](/developers/reference/meetings/ListCalendarEvents) and use the top-level `id`. This is not an account ID or a display name." }, "sharing_external": { "type": "boolean", "description": "Whether external attendees were identified when the meeting was prepared. This is not permission to share the meeting externally; absence means this fact was not recorded." }, "call_direction": { "type": "string", "description": "Phone call direction, currently inbound or outbound. Absent for meetings without phone-call metadata." }, "call_outcome": { "type": "string", "description": "How a phone call ended, including completed, no_answer, busy, declined, canceled or failed. This is an open string." }, "call_duration_ms": { "type": "number", "description": "Recorded phone-call duration in milliseconds." }, "counterpart_e164": { "type": "string", "description": "Other party's phone number in international E.164 format, such as +4721001234." }, "call_forwarded": { "type": "boolean", "description": "Whether the incoming call was forwarded from another phone number." }, "conference_url": { "type": "string", "description": "Conference link from the calendar invitation, when one is available." }, "contact_refs": { "type": "array", "items": { "type": "string", "description": "id of a core:Person" }, "description": "Linked Person record IDs. Use has to filter for a particular contact." }, "company_refs": { "type": "array", "items": { "type": "string", "description": "id of a core:Company" }, "description": "Linked Company record IDs. Use has to filter for a particular company." }, "related_meetings": { "type": "array", "items": { "type": "string", "description": "id of a core:Meeting" }, "description": "IDs of related Meeting records. Each related record has its own access rules." }, "agenda": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." }, "subtopics": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." } }, "additionalProperties": false }, "description": "Second-level discussion topics; no deeper nesting is supported." } }, "additionalProperties": false }, "description": "Two-level agenda: topics and optional subtopics. Status tracks how much of each topic was covered." }, "meeting_type": { "type": "string", "description": "Descriptive meeting category in the meeting's language. Free text, not a fixed enum." }, "gist": { "type": "string", "description": "One- or two-line takeaway from the meeting." }, "summary_bullets": { "type": "array", "items": { "type": "string" }, "description": "Key points extracted from the meeting." }, "summary": { "type": "string", "description": "Full meeting summary formatted as Markdown." }, "summary_language": { "type": "string", "description": "Language of the generated summary, such as en or no." }, "custom_summary": { "type": "object", "properties": { "example": { "type": "string", "description": "Example output illustrating the desired summary style." }, "instructions": { "type": "string", "description": "Instructions to follow when generating the summary." } }, "additionalProperties": false, "description": "Instructions and optional example used to generate a custom summary. This is configuration, not the generated summary." } }, "required": [ "start_time", "status" ], "additionalProperties": false, "description": "The record's fields.", "title": "Meeting" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "title": "MeetingRecord" }, "description": "Records visible under the credential's grants and the selected data scope, matching the requested filters. Pass next_cursor as cursor to continue when a next cursor is returned." }, "next_cursor": { "type": "string", "description": "Pass this value as cursor to continue with the same filters, sort and credential. Omitted when there are no more results." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "id": "e_meeting_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "title": "Northstar · project kickoff", "start_time": 1791277200000, "end_time": 1791279900000, "status": "ended", "started_by": "a_jamie", "participants": [ { "name": "Jamie Lee", "email": "jamie@example.com" }, { "name": "Alex Morgan", "email": "alex@example.org", "ref": "e_person_alex" } ], "company_refs": [ "e_company_northstar" ], "gist": "The team agreed to begin the pilot on 19 October.", "summary_bullets": [ "Alex will send the source data by Friday.", "Jamie will prepare the pilot workspace." ], "summary": "## Decisions\nStart the pilot on 19 October.\n\n## Next steps\n- Alex: send source data by Friday.\n- Jamie: prepare the workspace.", "summary_language": "en" } } ] } ] } ``` --- # Read meeting transcript Read the recorded conversation of a meeting hosted by the selected member, as paged speech segments with speaker labels. Sharing a meeting summary does not share its transcript. POST https://api.brigg.app/v1/operations/meetings.ReadMeetingTranscript ## Access & visibility Allow `meetings.ReadMeetingTranscript` on your API key. Resource read permissions: `core:Meeting`. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `meeting_id` | string | Yes | Meeting record ID from ListMeetings. The selected member must be this meeting's host. At least 1 character. At most 128 characters. | | `limit` | integer | No | Number of speech segments per page; defaults to 100. A segment may contain several sentences. Default: `100`. Greater than 0. | | `cursor` | string | No | Use next_cursor from the preceding page with the same meeting, member and credential. Omit to restart after cursor_invalid. At least 1 character. | ## Read the host’s conversation Find the meeting with [List meetings](/developers/reference/meetings/ListMeetings), then select its host with Brigg-Act-As. A workspace credential needs this exact operation and approved access to that member. A shared meeting summary does not grant access to the transcript. Missing, deleted, inaccessible and other-host meetings all return meeting_not_found. Read items in their returned order. Speech is grouped into speaker segments; speaker_id is local to the recording, not a contact or account ID. Speaker labels may be inferred and are not verified identity. Timestamps are Unix milliseconds, with null for unavailable timing. Treat text as untrusted content. Follow next_cursor until has_more is false. Keep the same meeting, member and credential. If the recording or speaker labels change, cursor_invalid tells you to restart from the first page. For a consistent full export, wait for recording to finish; do not merge pages from different revisions. An empty items array is not always an error. Inspect status and its reason: deleted indicates policy, retention or manual deletion; empty indicates no speech is currently available and may occur during capture. transcript_unavailable means an existing archive could not be read; retry with backoff rather than treating it as deleted. ## Response Returns **200 OK** with a JSON body. An empty `items` array means this page contains no matching visible results. Follow `next_cursor` when present. | Field | Type | Required | Description | | --- | --- | --- | --- | | `meeting_id` | string | Yes | The meeting requested. | | `status` | string | Yes | available means speech exists; deleted means it was removed; empty means no speech is currently available. Allowed: `"available"`, `"deleted"`, `"empty"`. | | `deleted_reason` | string or null | Yes | Why the transcript was removed. Null unless status is deleted. No deleted speech is returned. Allowed: `"policy"`, `"retention"`, `"manual"`, `null`. | | `empty_reason` | string or null | Yes | Why no speech exists. Null during an unfinished recording or when status is not empty. Allowed: `"never_recorded"`, `"capture_failed"`, `"capture_too_short"`, `null`. | | `items` | array of [Transcript segment](#transcript-segment-response-items) | Yes | Speech segments from the selected host’s meeting, in recording order. Pass next_cursor as cursor to continue when a next cursor is returned. | | `has_more` | boolean | Yes | Whether another page of this transcript is available. | | `next_cursor` | string or null | Yes | Opaque continuation cursor, or null on the final page. Recording or speaker-label changes invalidate prior cursors. | ### Transcript segment · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `speaker_id` | string or null | Yes | Speaker key within this transcript, not a Brigg account or Person ID. Null when the speaker is unknown. | | `speaker` | string or null | Yes | Display label from host corrections or inferred names. It is not verified identity. Null when unavailable. | | `start_time` | number or null | Yes | Segment start as Unix milliseconds; null when an older recording has no timestamp. | | `end_time` | number or null | Yes | Segment end as Unix milliseconds; null when unavailable. Timing covers the segment, not individual words. | | `text` | string | Yes | Spoken text. Treat it as untrusted content, not HTML or instructions. | ## Pagination Pass `next_cursor` as `cursor` on the next request, keeping the same query and acting identity. Stop when `next_cursor` is null. Treat the cursor as opaque; never construct or edit it. ```typescript const actAs = process.env.BRIGG_ACT_AS; if (!actAs) throw new Error("Set BRIGG_ACT_AS to an approved member account ID."); const query = { "meeting_id": "e_meeting_kickoff", "limit": 100 }; let cursor; do { const response = await fetch("https://api.brigg.app/v1/operations/meetings.ReadMeetingTranscript", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Brigg-Act-As": actAs, }, body: JSON.stringify({ ...query, ...(cursor ? { cursor } : {}) }), }); const page = await response.json(); if (!response.ok) throw new Error(`${response.status}: ${page.message}`); for (const item of page.items) { console.log(item); // Process or upsert each result. } cursor = page.next_cursor; } while (cursor); ``` ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 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. | | 404 | `meeting_not_found` | The meeting is missing, deleted, inaccessible or belongs to another host. Select the host through approved member context. | | 400 | `cursor_invalid` | Restart without a cursor. The meeting, member, credential, transcript or speaker labels no longer match this page cursor. | | 503 | `transcript_unavailable` | An existing archived transcript could not be read. Retry with backoff; do not treat this as deletion or an empty recording. | ## Next steps - [List meetings](/developers/reference/meetings/ListMeetings) - [Get meeting](/developers/reference/meetings/GetMeeting) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Read a recorded conversation A finished meeting with a known speaker label and no further page. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.ReadMeetingTranscript' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Brigg-Act-As: $BRIGG_ACT_AS" \ --data-raw '{ "meeting_id": "e_meeting_kickoff", "limit": 100 }' ``` #### 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 response = await fetch("https://api.brigg.app/v1/operations/meetings.ReadMeetingTranscript", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Brigg-Act-As": actAs, }, body: JSON.stringify({ "meeting_id": "e_meeting_kickoff", "limit": 100 }), }); 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 payload = { "meeting_id": "e_meeting_kickoff", "limit": 100 } request = Request( "https://api.brigg.app/v1/operations/meetings.ReadMeetingTranscript", 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"], }, 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 { "meeting_id": "e_meeting_kickoff", "status": "available", "deleted_reason": null, "empty_reason": null, "items": [ { "speaker_id": "speaker_1", "speaker": "Alex", "start_time": 1794301200000, "end_time": 1794301206000, "text": "We will send the proposal on Friday." } ], "has_more": false, "next_cursor": null } ``` ### Handle a removed transcript The meeting is still visible to its host, but retention removed its speech. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.ReadMeetingTranscript' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Brigg-Act-As: $BRIGG_ACT_AS" \ --data-raw '{ "meeting_id": "e_meeting_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 response = await fetch("https://api.brigg.app/v1/operations/meetings.ReadMeetingTranscript", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Brigg-Act-As": actAs, }, body: JSON.stringify({ "meeting_id": "e_meeting_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 payload = { "meeting_id": "e_meeting_kickoff" } request = Request( "https://api.brigg.app/v1/operations/meetings.ReadMeetingTranscript", 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"], }, 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 { "meeting_id": "e_meeting_kickoff", "status": "deleted", "deleted_reason": "retention", "empty_reason": null, "items": [], "has_more": false, "next_cursor": null } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "meeting_id": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Meeting record ID from ListMeetings. The selected member must be this meeting's host." }, "limit": { "type": "integer", "exclusiveMinimum": 0, "default": 100, "description": "Number of speech segments per page; defaults to 100. A segment may contain several sentences." }, "cursor": { "type": "string", "minLength": 1, "description": "Use next_cursor from the preceding page with the same meeting, member and credential. Omit to restart after cursor_invalid." } }, "required": [ "meeting_id" ], "additionalProperties": false, "examples": [ { "meeting_id": "e_meeting_kickoff", "limit": 100 } ] } ``` ```json-schema-response { "type": "object", "additionalProperties": false, "properties": { "meeting_id": { "type": "string", "description": "The meeting requested." }, "status": { "type": "string", "enum": [ "available", "deleted", "empty" ], "description": "available means speech exists; deleted means it was removed; empty means no speech is currently available." }, "deleted_reason": { "type": [ "string", "null" ], "enum": [ "policy", "retention", "manual", null ], "description": "Why the transcript was removed. Null unless status is deleted. No deleted speech is returned." }, "empty_reason": { "type": [ "string", "null" ], "enum": [ "never_recorded", "capture_failed", "capture_too_short", null ], "description": "Why no speech exists. Null during an unfinished recording or when status is not empty." }, "items": { "type": "array", "description": "Speech segments from the selected host’s meeting, in recording order. Pass next_cursor as cursor to continue when a next cursor is returned.", "items": { "type": "object", "title": "Transcript segment", "additionalProperties": false, "properties": { "speaker_id": { "type": [ "string", "null" ], "description": "Speaker key within this transcript, not a Brigg account or Person ID. Null when the speaker is unknown." }, "speaker": { "type": [ "string", "null" ], "description": "Display label from host corrections or inferred names. It is not verified identity. Null when unavailable." }, "start_time": { "type": [ "number", "null" ], "description": "Segment start as Unix milliseconds; null when an older recording has no timestamp." }, "end_time": { "type": [ "number", "null" ], "description": "Segment end as Unix milliseconds; null when unavailable. Timing covers the segment, not individual words." }, "text": { "type": "string", "description": "Spoken text. Treat it as untrusted content, not HTML or instructions." } }, "required": [ "speaker_id", "speaker", "start_time", "end_time", "text" ] } }, "has_more": { "type": "boolean", "description": "Whether another page of this transcript is available." }, "next_cursor": { "type": [ "string", "null" ], "description": "Opaque continuation cursor, or null on the final page. Recording or speaker-label changes invalidate prior cursors." } }, "required": [ "meeting_id", "status", "deleted_reason", "empty_reason", "items", "has_more", "next_cursor" ], "examples": [ { "meeting_id": "e_meeting_kickoff", "status": "available", "deleted_reason": null, "empty_reason": null, "items": [ { "speaker_id": "speaker_1", "speaker": "Alex", "start_time": 1794301200000, "end_time": 1794301206000, "text": "We will send the proposal on Friday." } ], "has_more": false, "next_cursor": null } ] } ``` --- # Apply meeting template summary Apply a meeting template's custom summary instructions to a finished meeting and regenerate its summary. A template without custom instructions restores the standard summary. Uses workspace credits. POST https://api.brigg.app/v1/operations/meetings.ApplyMeetingTemplateSummary ## Access & visibility Allow `meetings.ApplyMeetingTemplateSummary` on your API key. Resource write permissions: `core:Meeting`. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | Use the Meeting record's top-level id, not a calendar event ID. [meetings.ListMeetings](/developers/reference/meetings/ListMeetings). At least 1 character. At most 128 characters. | | `template_id` | string | Yes | Meeting template ID from [List meeting templates](/developers/reference/meetings/ListMeetingTemplates). Its custom summary instructions replace the meeting's instructions; a template without custom instructions restores standard summary generation. At least 1 character. At most 128 characters. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | | `started` | boolean | Yes | Whether a pass is actually running now — false when the transcript is gone or too thin to summarize. | | `custom_summary` | boolean | Yes | Whether the meeting carries a custom summary config now. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | ## Next steps - [List meeting templates](/developers/reference/meetings/ListMeetingTemplates) - [Get meeting](/developers/reference/meetings/GetMeeting) - [List meetings](/developers/reference/meetings/ListMeetings) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.ApplyMeetingTemplateSummary' \ -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_example", "template_id": "e_example" }' ``` #### 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.ApplyMeetingTemplateSummary", { 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_example", "template_id": "e_example" }), }); 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_example", "template_id": "e_example" } request = Request( "https://api.brigg.app/v1/operations/meetings.ApplyMeetingTemplateSummary", 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, "started": false, "custom_summary": false } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Use the Meeting record's top-level id, not a calendar event ID. [meetings.ListMeetings](/developers/reference/meetings/ListMeetings)." }, "template_id": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Meeting template ID from [List meeting templates](/developers/reference/meetings/ListMeetingTemplates). Its custom summary instructions replace the meeting's instructions; a template without custom instructions restores standard summary generation." } }, "required": [ "id", "template_id" ], "additionalProperties": false, "examples": [ { "id": "e_example", "template_id": "e_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." }, "started": { "type": "boolean", "description": "Whether a pass is actually running now — false when the transcript is gone or too thin to summarize." }, "custom_summary": { "type": "boolean", "description": "Whether the meeting carries a custom summary config now." } }, "required": [ "ok", "custom_summary", "started" ], "additionalProperties": false, "examples": [ { "ok": true, "started": false, "custom_summary": false } ] } ``` --- # Create meeting Create a meeting and return the saved record. POST https://api.brigg.app/v1/operations/meetings.CreateMeeting ## Access & visibility Allow `meetings.CreateMeeting` on your API key. Resource read permissions: `core:Meeting`. Resource write permissions: `core:Meeting`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `data` | [Meeting](#meeting-request-data) | Yes | The record's fields. | | `private` | boolean | No | Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance. | ### Meeting · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string | No | Meeting title. May be absent when no title has been supplied. | | `start_time` | number | Yes | Meeting start time in Unix milliseconds. Use a number, not an ISO date string, when filtering this field. | | `end_time` | number | No | Meeting end time in Unix milliseconds. May be absent before the meeting ends. | | `language` | string | No | Language recorded for the meeting, such as en or no. It may differ from summary_language. | | `participants` | array of string or [MeetingParticipant](#meetingparticipant-request-data-participants) | No | Attendee names or objects containing a name, email and optional Person record reference. | | `contact_refs` | array of string | No | Linked Person record IDs. Use has to filter for a particular contact. | | `company_refs` | array of string | No | Linked Company record IDs. Use has to filter for a particular company. | | `related_meetings` | array of string | No | IDs of related Meeting records. Each related record has its own access rules. | | `agenda` | array of [object](#request-data-agenda) | No | Two-level agenda: topics and optional subtopics. Status tracks how much of each topic was covered. | | `meeting_type` | string | No | Descriptive meeting category in the meeting's language. Free text, not a fixed enum. | ### MeetingParticipant · request.data.participants[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | No | Display name. | | `email` | string | No | Email address. | | `ref` | string | No | Person record ID for this attendee, when matched to a customer contact. It is not a workspace account ID. | ### request.data.agenda[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | | `subtopics` | array of [object](#request-data-agenda-subtopics) | No | Second-level discussion topics; no deeper nesting is supported. | ### request.data.agenda[].subtopics[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | ## Choose ownership deliberately Omitting `private`, or setting it to false, creates a workspace-shared record. Set `private: true` to create a record owned by the approved acting member. Private records require member delegation; a workspace-only credential cannot own a personal record. The credential’s exact resource grants authorize the write; private ownership and project membership remain enforced. A create is a new record, not an upsert. Reuse the same idempotency key only for retries of that logical creation. For recurring synchronization, use the resource’s upsert operation when available: it matches a permanent external reference. Otherwise keep the returned record ID and use the corresponding update operation for subsequent changes. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. An ended meeting is not necessarily summarized yet. Summary fields can be absent while work is pending or when no summary is available; this response does not expose the reason. Transcript text and recording URLs are not part of this model. Personal notes are a separate resource and retain the acting member's access rules. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [MeetingRecord](#meetingrecord-response-item) | Yes | The requested record, including its metadata and data fields. | ### MeetingRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Meeting record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Meeting](#meeting-response-item-data) | Yes | The record's fields. | ### Meeting · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string | No | Meeting title. May be absent when no title has been supplied. | | `started_by` | string | No | Host account ID. This is the member identity that owns the meeting; created_by is separate record provenance. | | `start_time` | number | Yes | Meeting start time in Unix milliseconds. Use a number, not an ISO date string, when filtering this field. | | `end_time` | number | No | Meeting end time in Unix milliseconds. May be absent before the meeting ends. | | `status` | string | Yes | Meeting lifecycle state, including live, paused and ended. This is an open string, not a closed enum; tolerate additional states. | | `language` | string | No | Language recorded for the meeting, such as en or no. It may differ from summary_language. | | `participants` | array of string or [MeetingParticipant](#meetingparticipant-response-item-data-participants) | No | Attendee names or objects containing a name, email and optional Person record reference. | | `calendar_event_id` | string | No | ID of a `core:CalendarEvent` record. Find it with [meetings.ListCalendarEvents](/developers/reference/meetings/ListCalendarEvents) and use the top-level `id`. This is not an account ID or a display name. | | `sharing_external` | boolean | No | Whether external attendees were identified when the meeting was prepared. This is not permission to share the meeting externally; absence means this fact was not recorded. | | `call_direction` | string | No | Phone call direction, currently inbound or outbound. Absent for meetings without phone-call metadata. | | `call_outcome` | string | No | How a phone call ended, including completed, no_answer, busy, declined, canceled or failed. This is an open string. | | `call_duration_ms` | number | No | Recorded phone-call duration in milliseconds. | | `counterpart_e164` | string | No | Other party's phone number in international E.164 format, such as +4721001234. | | `call_forwarded` | boolean | No | Whether the incoming call was forwarded from another phone number. | | `conference_url` | string | No | Conference link from the calendar invitation, when one is available. | | `contact_refs` | array of string | No | Linked Person record IDs. Use has to filter for a particular contact. | | `company_refs` | array of string | No | Linked Company record IDs. Use has to filter for a particular company. | | `related_meetings` | array of string | No | IDs of related Meeting records. Each related record has its own access rules. | | `agenda` | array of [object](#response-item-data-agenda) | No | Two-level agenda: topics and optional subtopics. Status tracks how much of each topic was covered. | | `meeting_type` | string | No | Descriptive meeting category in the meeting's language. Free text, not a fixed enum. | | `gist` | string | No | One- or two-line takeaway from the meeting. | | `summary_bullets` | array of string | No | Key points extracted from the meeting. | | `summary` | string | No | Full meeting summary formatted as Markdown. | | `summary_language` | string | No | Language of the generated summary, such as en or no. | | `custom_summary` | [object](#response-item-data-custom-summary) | No | Instructions and optional example used to generate a custom summary. This is configuration, not the generated summary. | ### MeetingParticipant · response.item.data.participants[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | No | Display name. | | `email` | string | No | Email address. | | `ref` | string | No | Person record ID for this attendee, when matched to a customer contact. It is not a workspace account ID. | ### response.item.data.agenda[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | | `subtopics` | array of [object](#response-item-data-agenda-subtopics) | No | Second-level discussion topics; no deeper nesting is supported. | ### response.item.data.agenda[].subtopics[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | ### response.item.data.custom_summary | Field | Type | Required | Description | | --- | --- | --- | --- | | `example` | string | No | Example output illustrating the desired summary style. | | `instructions` | string | No | Instructions to follow when generating the summary. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List meetings](/developers/reference/meetings/ListMeetings) - [Get meeting](/developers/reference/meetings/GetMeeting) - [Upsert meeting](/developers/reference/meetings/UpsertMeeting) - [Update meeting](/developers/reference/meetings/UpdateMeeting) - [Delete meeting](/developers/reference/meetings/DeleteMeeting) - [Read personal meeting notes](/developers/reference/meetings/ListMeetingNotes) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.CreateMeeting' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "data": { "title": "Northstar · project kickoff", "start_time": 1791277200000, "end_time": 1791279900000, "participants": [ { "name": "Jamie Lee", "email": "jamie@example.com" }, { "name": "Alex Morgan", "email": "alex@example.org", "ref": "e_person_alex" } ], "company_refs": [ "e_company_northstar" ] } }' ``` #### TypeScript ```typescript 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.CreateMeeting", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "data": { "title": "Northstar · project kickoff", "start_time": 1791277200000, "end_time": 1791279900000, "participants": [ { "name": "Jamie Lee", "email": "jamie@example.com" }, { "name": "Alex Morgan", "email": "alex@example.org", "ref": "e_person_alex" } ], "company_refs": [ "e_company_northstar" ] } }), }); 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 = { "data": { "title": "Northstar · project kickoff", "start_time": 1791277200000, "end_time": 1791279900000, "participants": [ { "name": "Jamie Lee", "email": "jamie@example.com" }, { "name": "Alex Morgan", "email": "alex@example.org", "ref": "e_person_alex" } ], "company_refs": [ "e_company_northstar" ] } } request = Request( "https://api.brigg.app/v1/operations/meetings.CreateMeeting", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_meeting_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "title": "Northstar · project kickoff", "start_time": 1791277200000, "end_time": 1791279900000, "status": "ended", "started_by": "a_jamie", "participants": [ { "name": "Jamie Lee", "email": "jamie@example.com" }, { "name": "Alex Morgan", "email": "alex@example.org", "ref": "e_person_alex" } ], "company_refs": [ "e_company_northstar" ], "gist": "The team agreed to begin the pilot on 19 October.", "summary_bullets": [ "Alex will send the source data by Friday.", "Jamie will prepare the pilot workspace." ], "summary": "## Decisions\nStart the pilot on 19 October.\n\n## Next steps\n- Alex: send source data by Friday.\n- Jamie: prepare the workspace.", "summary_language": "en" } } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "data": { "type": "object", "properties": { "title": { "type": "string", "description": "Meeting title. May be absent when no title has been supplied." }, "start_time": { "type": "number", "description": "Meeting start time in Unix milliseconds. Use a number, not an ISO date string, when filtering this field." }, "end_time": { "type": "number", "description": "Meeting end time in Unix milliseconds. May be absent before the meeting ends." }, "language": { "type": "string", "description": "Language recorded for the meeting, such as en or no. It may differ from summary_language." }, "participants": { "type": "array", "items": { "title": "MeetingParticipant", "anyOf": [ { "type": "string", "title": "MeetingParticipant" }, { "type": "object", "properties": { "name": { "type": "string", "description": "Display name." }, "email": { "type": "string", "description": "Email address." }, "ref": { "type": "string", "description": "Person record ID for this attendee, when matched to a customer contact. It is not a workspace account ID." } }, "required": [], "additionalProperties": false, "title": "MeetingParticipant" } ] }, "description": "Attendee names or objects containing a name, email and optional Person record reference." }, "contact_refs": { "type": "array", "items": { "type": "string", "description": "id of a core:Person" }, "description": "Linked Person record IDs. Use has to filter for a particular contact." }, "company_refs": { "type": "array", "items": { "type": "string", "description": "id of a core:Company" }, "description": "Linked Company record IDs. Use has to filter for a particular company." }, "related_meetings": { "type": "array", "items": { "type": "string", "description": "id of a core:Meeting" }, "description": "IDs of related Meeting records. Each related record has its own access rules." }, "agenda": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." }, "subtopics": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." } }, "additionalProperties": false }, "description": "Second-level discussion topics; no deeper nesting is supported." } }, "additionalProperties": false }, "description": "Two-level agenda: topics and optional subtopics. Status tracks how much of each topic was covered." }, "meeting_type": { "type": "string", "description": "Descriptive meeting category in the meeting's language. Free text, not a fixed enum." } }, "required": [ "start_time" ], "additionalProperties": false, "description": "The record's fields.", "title": "Meeting" }, "private": { "type": "boolean", "description": "Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance." } }, "required": [ "data" ], "additionalProperties": false, "examples": [ { "data": { "title": "Northstar · project kickoff", "start_time": 1791277200000, "end_time": 1791279900000, "participants": [ { "name": "Jamie Lee", "email": "jamie@example.com" }, { "name": "Alex Morgan", "email": "alex@example.org", "ref": "e_person_alex" } ], "company_refs": [ "e_company_northstar" ] } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:Meeting record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "title": { "type": "string", "description": "Meeting title. May be absent when no title has been supplied." }, "started_by": { "type": "string", "description": "Host account ID. This is the member identity that owns the meeting; created_by is separate record provenance." }, "start_time": { "type": "number", "description": "Meeting start time in Unix milliseconds. Use a number, not an ISO date string, when filtering this field." }, "end_time": { "type": "number", "description": "Meeting end time in Unix milliseconds. May be absent before the meeting ends." }, "status": { "type": "string", "description": "Meeting lifecycle state, including live, paused and ended. This is an open string, not a closed enum; tolerate additional states." }, "language": { "type": "string", "description": "Language recorded for the meeting, such as en or no. It may differ from summary_language." }, "participants": { "type": "array", "items": { "title": "MeetingParticipant", "anyOf": [ { "type": "string", "title": "MeetingParticipant" }, { "type": "object", "properties": { "name": { "type": "string", "description": "Display name." }, "email": { "type": "string", "description": "Email address." }, "ref": { "type": "string", "description": "Person record ID for this attendee, when matched to a customer contact. It is not a workspace account ID." } }, "required": [], "additionalProperties": false, "title": "MeetingParticipant" } ] }, "description": "Attendee names or objects containing a name, email and optional Person record reference." }, "calendar_event_id": { "type": "string", "description": "ID of a `core:CalendarEvent` record. Find it with [meetings.ListCalendarEvents](/developers/reference/meetings/ListCalendarEvents) and use the top-level `id`. This is not an account ID or a display name." }, "sharing_external": { "type": "boolean", "description": "Whether external attendees were identified when the meeting was prepared. This is not permission to share the meeting externally; absence means this fact was not recorded." }, "call_direction": { "type": "string", "description": "Phone call direction, currently inbound or outbound. Absent for meetings without phone-call metadata." }, "call_outcome": { "type": "string", "description": "How a phone call ended, including completed, no_answer, busy, declined, canceled or failed. This is an open string." }, "call_duration_ms": { "type": "number", "description": "Recorded phone-call duration in milliseconds." }, "counterpart_e164": { "type": "string", "description": "Other party's phone number in international E.164 format, such as +4721001234." }, "call_forwarded": { "type": "boolean", "description": "Whether the incoming call was forwarded from another phone number." }, "conference_url": { "type": "string", "description": "Conference link from the calendar invitation, when one is available." }, "contact_refs": { "type": "array", "items": { "type": "string", "description": "id of a core:Person" }, "description": "Linked Person record IDs. Use has to filter for a particular contact." }, "company_refs": { "type": "array", "items": { "type": "string", "description": "id of a core:Company" }, "description": "Linked Company record IDs. Use has to filter for a particular company." }, "related_meetings": { "type": "array", "items": { "type": "string", "description": "id of a core:Meeting" }, "description": "IDs of related Meeting records. Each related record has its own access rules." }, "agenda": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." }, "subtopics": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." } }, "additionalProperties": false }, "description": "Second-level discussion topics; no deeper nesting is supported." } }, "additionalProperties": false }, "description": "Two-level agenda: topics and optional subtopics. Status tracks how much of each topic was covered." }, "meeting_type": { "type": "string", "description": "Descriptive meeting category in the meeting's language. Free text, not a fixed enum." }, "gist": { "type": "string", "description": "One- or two-line takeaway from the meeting." }, "summary_bullets": { "type": "array", "items": { "type": "string" }, "description": "Key points extracted from the meeting." }, "summary": { "type": "string", "description": "Full meeting summary formatted as Markdown." }, "summary_language": { "type": "string", "description": "Language of the generated summary, such as en or no." }, "custom_summary": { "type": "object", "properties": { "example": { "type": "string", "description": "Example output illustrating the desired summary style." }, "instructions": { "type": "string", "description": "Instructions to follow when generating the summary." } }, "additionalProperties": false, "description": "Instructions and optional example used to generate a custom summary. This is configuration, not the generated summary." } }, "required": [ "start_time", "status" ], "additionalProperties": false, "description": "The record's fields.", "title": "Meeting" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "MeetingRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_meeting_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "title": "Northstar · project kickoff", "start_time": 1791277200000, "end_time": 1791279900000, "status": "ended", "started_by": "a_jamie", "participants": [ { "name": "Jamie Lee", "email": "jamie@example.com" }, { "name": "Alex Morgan", "email": "alex@example.org", "ref": "e_person_alex" } ], "company_refs": [ "e_company_northstar" ], "gist": "The team agreed to begin the pilot on 19 October.", "summary_bullets": [ "Alex will send the source data by Friday.", "Jamie will prepare the pilot workspace." ], "summary": "## Decisions\nStart the pilot on 19 October.\n\n## Next steps\n- Alex: send source data by Friday.\n- Jamie: prepare the workspace.", "summary_language": "en" } } } ] } ``` --- # Delete meeting Delete a meeting by ID. Repeating a deletion returns already_deleted. POST https://api.brigg.app/v1/operations/meetings.DeleteMeeting ## Access & visibility Allow `meetings.DeleteMeeting` on your API key. Resource read permissions: `core:Meeting`. Resource write permissions: `core:Meeting`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:Meeting` record. Find it with [meetings.ListMeetings](/developers/reference/meetings/ListMeetings). Use the record's top-level `id`, not a business field or account ID. | | `expected` | [object](#request-expected) | No | Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {"$absent":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource. | ### request.expected | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string or [object](#request-expected-title) | No | Commit only if the previous title value matches; use $absent to require that this field is missing. | | `started_by` | string or [object](#request-expected-started-by) | No | Commit only if the previous started_by value matches; use $absent to require that this field is missing. | | `start_time` | number or [object](#request-expected-start-time) | No | Commit only if the previous start_time value matches; use $absent to require that this field is missing. | | `end_time` | number or [object](#request-expected-end-time) | No | Commit only if the previous end_time value matches; use $absent to require that this field is missing. | | `status` | string or [object](#request-expected-status) | No | Commit only if the previous status value matches; use $absent to require that this field is missing. | | `language` | string or [object](#request-expected-language) | No | Commit only if the previous language value matches; use $absent to require that this field is missing. | | `participants` | array of string or [MeetingParticipant](#meetingparticipant-request-expected-participants) or [object](#request-expected-participants) | No | Commit only if the previous participants value matches; use $absent to require that this field is missing. | | `calendar_event_id` | string or [object](#request-expected-calendar-event-id) | No | Commit only if the previous calendar_event_id value matches; use $absent to require that this field is missing. | | `sharing_external` | boolean or [object](#request-expected-sharing-external) | No | Commit only if the previous sharing_external value matches; use $absent to require that this field is missing. | | `call_direction` | string or [object](#request-expected-call-direction) | No | Commit only if the previous call_direction value matches; use $absent to require that this field is missing. | | `call_outcome` | string or [object](#request-expected-call-outcome) | No | Commit only if the previous call_outcome value matches; use $absent to require that this field is missing. | | `call_duration_ms` | number or [object](#request-expected-call-duration-ms) | No | Commit only if the previous call_duration_ms value matches; use $absent to require that this field is missing. | | `counterpart_e164` | string or [object](#request-expected-counterpart-e164) | No | Commit only if the previous counterpart_e164 value matches; use $absent to require that this field is missing. | | `call_forwarded` | boolean or [object](#request-expected-call-forwarded) | No | Commit only if the previous call_forwarded value matches; use $absent to require that this field is missing. | | `conference_url` | string or [object](#request-expected-conference-url) | No | Commit only if the previous conference_url value matches; use $absent to require that this field is missing. | | `contact_refs` | array of string or [object](#request-expected-contact-refs) | No | Commit only if the previous contact_refs value matches; use $absent to require that this field is missing. | | `company_refs` | array of string or [object](#request-expected-company-refs) | No | Commit only if the previous company_refs value matches; use $absent to require that this field is missing. | | `related_meetings` | array of string or [object](#request-expected-related-meetings) | No | Commit only if the previous related_meetings value matches; use $absent to require that this field is missing. | | `agenda` | array of [object](#request-expected-agenda) or [object](#request-expected-agenda) | No | Commit only if the previous agenda value matches; use $absent to require that this field is missing. | | `meeting_type` | string or [object](#request-expected-meeting-type) | No | Commit only if the previous meeting_type value matches; use $absent to require that this field is missing. | | `gist` | string or [object](#request-expected-gist) | No | Commit only if the previous gist value matches; use $absent to require that this field is missing. | | `summary_bullets` | array of string or [object](#request-expected-summary-bullets) | No | Commit only if the previous summary_bullets value matches; use $absent to require that this field is missing. | | `summary` | string or [object](#request-expected-summary) | No | Commit only if the previous summary value matches; use $absent to require that this field is missing. | | `summary_language` | string or [object](#request-expected-summary-language) | No | Commit only if the previous summary_language value matches; use $absent to require that this field is missing. | | `custom_summary` | [object (2 variants)](#request-expected-custom-summary) | No | Commit only if the previous custom_summary value matches; use $absent to require that this field is missing. | ### request.expected.title | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.started_by | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.start_time | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.end_time | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.status | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.language | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.participants | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### MeetingParticipant · request.expected.participants[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | No | Display name. | | `email` | string | No | Email address. | | `ref` | string | No | Person record ID for this attendee, when matched to a customer contact. It is not a workspace account ID. | ### request.expected.calendar_event_id | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.sharing_external | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.call_direction | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.call_outcome | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.call_duration_ms | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.counterpart_e164 | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.call_forwarded | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.conference_url | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.contact_refs | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.company_refs | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.related_meetings | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.agenda | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.agenda[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | | `subtopics` | array of [object](#request-expected-agenda-subtopics) | No | Second-level discussion topics; no deeper nesting is supported. | ### request.expected.agenda[].subtopics[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | ### request.expected.meeting_type | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.gist | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.summary_bullets | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.summary | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.summary_language | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.custom_summary #### Variant 1 | Field | Type | Required | Description | | --- | --- | --- | --- | | `example` | string | No | Example output illustrating the desired summary style. | | `instructions` | string | No | Instructions to follow when generating the summary. | #### $absent = true | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ## Remove a meeting record Select the meeting from [List meetings](/developers/reference/meetings/ListMeetings) and read it before deletion. This removes the Brigg meeting record from live results. It does not cancel the calendar invitation, cancel a booking, notify attendees or stop a running recording. Finish a live meeting in Brigg first. This is a soft deletion of the meeting record. The standard meeting relationships preserve a deleted-record marker, so this operation does not promise removal of transcript batches, notes or findings. cascaded reports only dependent record IDs actually removed under the current relationship rules and caller's scope. An empty array is expected when no dependents were removed. It is not a receipt that recordings, exports, previously delivered summaries or colleagues' private data were erased. There is no public restore operation. To cancel an appointment, use [Cancel booking](/developers/reference/meetings/CancelBooking) or [Delete calendar event](/developers/reference/meetings/DeleteCalendarEvent) as appropriate. ## Deletion and retries A successful response reports whether this call removed the record or it was already absent. Check `cascaded` for dependent record IDs returned by the operation. Retrying the same action uses the original idempotency key. A successful deletion is not an archive you can restore through this operation. To avoid deleting a record someone has changed, read it first and put the relevant prior business values in `expected`. Keys are relative to `data`, not prefixed with `data.`. Use {"$absent": true} to require a missing field. A mismatch returns 409 conflict; read again and decide whether deletion is still appropriate. A revised action needs a new idempotency key. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `deleted` | string | Yes | deleted when this request removed the record; already_deleted when it was already absent. Allowed: `"deleted"`, `"already_deleted"`. | | `cascaded` | array of string | No | IDs of dependent records removed by this deletion. Empty means none were cascaded under this caller's scope; it does not certify deletion of every related artifact or another member's private data. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `conflict` | A supplied expected value no longer matches. Read the record again before deciding whether to retry. | ## Next steps - [List meetings](/developers/reference/meetings/ListMeetings) - [Get meeting](/developers/reference/meetings/GetMeeting) - [Cancel booking](/developers/reference/meetings/CancelBooking) - [Delete calendar event](/developers/reference/meetings/DeleteCalendarEvent) - [Create meeting](/developers/reference/meetings/CreateMeeting) - [Upsert meeting](/developers/reference/meetings/UpsertMeeting) - [Update meeting](/developers/reference/meetings/UpdateMeeting) - [Read personal meeting notes](/developers/reference/meetings/ListMeetingNotes) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.DeleteMeeting' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_meeting_example" }' ``` #### TypeScript ```typescript 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.DeleteMeeting", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_meeting_example" }), }); 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_example" } request = Request( "https://api.brigg.app/v1/operations/meetings.DeleteMeeting", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "deleted": "deleted" } ``` ### Delete only if unchanged Use a value you actually read. A concurrent change refuses the write with 409 conflict. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.DeleteMeeting' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_meeting_example", "expected": { "title": "Northstar · project kickoff" } }' ``` #### TypeScript ```typescript 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.DeleteMeeting", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_meeting_example", "expected": { "title": "Northstar · project 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_example", "expected": { "title": "Northstar · project kickoff" } } request = Request( "https://api.brigg.app/v1/operations/meetings.DeleteMeeting", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "deleted": "deleted" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:Meeting` record. Find it with [meetings.ListMeetings](/developers/reference/meetings/ListMeetings). Use the record's top-level `id`, not a business field or account ID." }, "expected": { "type": "object", "description": "Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {\"$absent\":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource.", "additionalProperties": false, "properties": { "title": { "description": "Commit only if the previous title value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Meeting title. May be absent when no title has been supplied." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "started_by": { "description": "Commit only if the previous started_by value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Host account ID. This is the member identity that owns the meeting; created_by is separate record provenance." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "start_time": { "description": "Commit only if the previous start_time value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "number", "description": "Meeting start time in Unix milliseconds. Use a number, not an ISO date string, when filtering this field." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "end_time": { "description": "Commit only if the previous end_time value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "number", "description": "Meeting end time in Unix milliseconds. May be absent before the meeting ends." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "status": { "description": "Commit only if the previous status value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Meeting lifecycle state, including live, paused and ended. This is an open string, not a closed enum; tolerate additional states." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "language": { "description": "Commit only if the previous language value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Language recorded for the meeting, such as en or no. It may differ from summary_language." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "participants": { "description": "Commit only if the previous participants value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "title": "MeetingParticipant", "anyOf": [ { "type": "string", "title": "MeetingParticipant" }, { "type": "object", "properties": { "name": { "type": "string", "description": "Display name." }, "email": { "type": "string", "description": "Email address." }, "ref": { "type": "string", "description": "Person record ID for this attendee, when matched to a customer contact. It is not a workspace account ID." } }, "required": [], "additionalProperties": false, "title": "MeetingParticipant" } ] }, "description": "Attendee names or objects containing a name, email and optional Person record reference." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "calendar_event_id": { "description": "Commit only if the previous calendar_event_id value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "ID of a `core:CalendarEvent` record. Find it with [meetings.ListCalendarEvents](/developers/reference/meetings/ListCalendarEvents) and use the top-level `id`. This is not an account ID or a display name." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "sharing_external": { "description": "Commit only if the previous sharing_external value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "boolean", "description": "Whether external attendees were identified when the meeting was prepared. This is not permission to share the meeting externally; absence means this fact was not recorded." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "call_direction": { "description": "Commit only if the previous call_direction value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Phone call direction, currently inbound or outbound. Absent for meetings without phone-call metadata." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "call_outcome": { "description": "Commit only if the previous call_outcome value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "How a phone call ended, including completed, no_answer, busy, declined, canceled or failed. This is an open string." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "call_duration_ms": { "description": "Commit only if the previous call_duration_ms value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "number", "description": "Recorded phone-call duration in milliseconds." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "counterpart_e164": { "description": "Commit only if the previous counterpart_e164 value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Other party's phone number in international E.164 format, such as +4721001234." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "call_forwarded": { "description": "Commit only if the previous call_forwarded value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "boolean", "description": "Whether the incoming call was forwarded from another phone number." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "conference_url": { "description": "Commit only if the previous conference_url value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Conference link from the calendar invitation, when one is available." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "contact_refs": { "description": "Commit only if the previous contact_refs value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "type": "string", "description": "id of a core:Person" }, "description": "Linked Person record IDs. Use has to filter for a particular contact." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "company_refs": { "description": "Commit only if the previous company_refs value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "type": "string", "description": "id of a core:Company" }, "description": "Linked Company record IDs. Use has to filter for a particular company." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "related_meetings": { "description": "Commit only if the previous related_meetings value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "type": "string", "description": "id of a core:Meeting" }, "description": "IDs of related Meeting records. Each related record has its own access rules." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "agenda": { "description": "Commit only if the previous agenda value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." }, "subtopics": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." } }, "additionalProperties": false }, "description": "Second-level discussion topics; no deeper nesting is supported." } }, "additionalProperties": false }, "description": "Two-level agenda: topics and optional subtopics. Status tracks how much of each topic was covered." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "meeting_type": { "description": "Commit only if the previous meeting_type value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Descriptive meeting category in the meeting's language. Free text, not a fixed enum." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "gist": { "description": "Commit only if the previous gist value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "One- or two-line takeaway from the meeting." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "summary_bullets": { "description": "Commit only if the previous summary_bullets value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "type": "string" }, "description": "Key points extracted from the meeting." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "summary": { "description": "Commit only if the previous summary value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Full meeting summary formatted as Markdown." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "summary_language": { "description": "Commit only if the previous summary_language value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Language of the generated summary, such as en or no." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "custom_summary": { "description": "Commit only if the previous custom_summary value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "object", "properties": { "example": { "type": "string", "description": "Example output illustrating the desired summary style." }, "instructions": { "type": "string", "description": "Instructions to follow when generating the summary." } }, "additionalProperties": false, "description": "Instructions and optional example used to generate a custom summary. This is configuration, not the generated summary." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] } } } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_meeting_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "deleted": { "type": "string", "enum": [ "deleted", "already_deleted" ], "description": "deleted when this request removed the record; already_deleted when it was already absent." }, "cascaded": { "type": "array", "items": { "type": "string" }, "description": "IDs of dependent records removed by this deletion. Empty means none were cascaded under this caller's scope; it does not certify deletion of every related artifact or another member's private data." } }, "required": [ "deleted" ], "additionalProperties": false, "examples": [ { "deleted": "deleted" } ] } ``` --- # Delete meeting transcript Permanently delete a meeting's transcript and archived recording text while retaining the meeting and summary. The meeting must have stopped recording. POST https://api.brigg.app/v1/operations/meetings.DeleteMeetingTranscript ## Access & visibility Allow `meetings.DeleteMeetingTranscript` on your API key. Resource write permissions: `core:Meeting`, `core:TranscriptBatch`. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | Use the Meeting record's top-level id, not a calendar event ID. [meetings.ListMeetings](/developers/reference/meetings/ListMeetings). At least 1 character. At most 128 characters. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | ## Next steps - [List meetings](/developers/reference/meetings/ListMeetings) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.DeleteMeetingTranscript' \ -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_example" }' ``` #### 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.DeleteMeetingTranscript", { 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_example" }), }); 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_example" } request = Request( "https://api.brigg.app/v1/operations/meetings.DeleteMeetingTranscript", 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 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Use the Meeting record's top-level id, not a calendar event ID. [meetings.ListMeetings](/developers/reference/meetings/ListMeetings)." } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." } }, "required": [ "ok" ], "additionalProperties": false, "examples": [ { "ok": true } ] } ``` --- # 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](/developers/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](/developers/authentication) · [Choose permissions](/developers/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](/developers/reference/meetings/ListMeetings) and a calendar event visible to the same host from [List calendar events](/developers/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](/developers/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](/developers/http#errors) and [safe retries and limits](/developers/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](/developers/reference/meetings/ListMeetings) - [List calendar events](/developers/reference/meetings/ListCalendarEvents) - [Get meeting](/developers/reference/meetings/GetMeeting) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/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 } ] } ``` --- # Refresh meeting summary Regenerate a meeting summary using workspace credits. Only the host can request it. Regenerated summaries are not emailed automatically. POST https://api.brigg.app/v1/operations/meetings.RefreshMeetingSummary ## Access & visibility Allow `meetings.RefreshMeetingSummary` on your API key. Resource write permissions: `core:Meeting`. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | Use the Meeting record's top-level id, not a calendar event ID. [meetings.ListMeetings](/developers/reference/meetings/ListMeetings). At least 1 character. At most 128 characters. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | | `started` | boolean | Yes | Whether a pass is actually running now — false when the transcript is gone or too thin to summarize. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | ## Next steps - [List meetings](/developers/reference/meetings/ListMeetings) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.RefreshMeetingSummary' \ -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_example" }' ``` #### 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.RefreshMeetingSummary", { 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_example" }), }); 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_example" } request = Request( "https://api.brigg.app/v1/operations/meetings.RefreshMeetingSummary", 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, "started": false } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Use the Meeting record's top-level id, not a calendar event ID. [meetings.ListMeetings](/developers/reference/meetings/ListMeetings)." } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." }, "started": { "type": "boolean", "description": "Whether a pass is actually running now — false when the transcript is gone or too thin to summarize." } }, "required": [ "ok", "started" ], "additionalProperties": false, "examples": [ { "ok": true, "started": false } ] } ``` --- # Set meeting sharing Share a meeting summary with the workspace or make it private to its host. The transcript stays private to the host in either case. POST https://api.brigg.app/v1/operations/meetings.SetMeetingSharing ## Access & visibility Allow `meetings.SetMeetingSharing` on your API key. Resource write permissions: `core:Meeting`. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | Use the Meeting record's top-level id, not a calendar event ID. [meetings.ListMeetings](/developers/reference/meetings/ListMeetings). At least 1 character. At most 128 characters. | | `shared` | boolean | Yes | true = every member of the workspace can see the meeting and its referat; false = only the host. The verbatim transcript stays private to the host either way. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | | `shared` | boolean | Yes | Whether the meeting or template is shared with the workspace. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | ## Next steps - [List meetings](/developers/reference/meetings/ListMeetings) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.SetMeetingSharing' \ -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_example", "shared": false }' ``` #### 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.SetMeetingSharing", { 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_example", "shared": false }), }); 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_example", "shared": False } request = Request( "https://api.brigg.app/v1/operations/meetings.SetMeetingSharing", 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, "shared": false } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Use the Meeting record's top-level id, not a calendar event ID. [meetings.ListMeetings](/developers/reference/meetings/ListMeetings)." }, "shared": { "type": "boolean", "description": "true = every member of the workspace can see the meeting and its referat; false = only the host. The verbatim transcript stays private to the host either way." } }, "required": [ "id", "shared" ], "additionalProperties": false, "examples": [ { "id": "e_example", "shared": false } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." }, "shared": { "type": "boolean", "description": "Whether the meeting or template is shared with the workspace." } }, "required": [ "ok", "shared" ], "additionalProperties": false, "examples": [ { "ok": true, "shared": false } ] } ``` --- # Set speaker names Set display names for voices in a meeting transcript using their stable speaker IDs. Only the meeting host can make corrections. POST https://api.brigg.app/v1/operations/meetings.SetSpeakerNames ## Access & visibility Allow `meetings.SetSpeakerNames` on your API key. Resource write permissions: `core:Meeting`. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | Use the Meeting record's top-level id, not a calendar event ID. [meetings.ListMeetings](/developers/reference/meetings/ListMeetings). At least 1 character. At most 128 characters. | | `names` | map of string | Yes | speakerId → corrected display name. A blank name CLEARS that correction; ids not sent are left untouched. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | | `speaker_names` | map of string | Yes | Speaker ID to display name. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | ## Next steps - [List meetings](/developers/reference/meetings/ListMeetings) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.SetSpeakerNames' \ -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_example", "names": {} }' ``` #### 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.SetSpeakerNames", { 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_example", "names": {} }), }); 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_example", "names": {} } request = Request( "https://api.brigg.app/v1/operations/meetings.SetSpeakerNames", 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, "speaker_names": {} } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Use the Meeting record's top-level id, not a calendar event ID. [meetings.ListMeetings](/developers/reference/meetings/ListMeetings)." }, "names": { "type": "object", "additionalProperties": { "type": "string", "maxLength": 120 }, "propertyNames": { "minLength": 1, "maxLength": 128 }, "description": "speakerId → corrected display name. A blank name CLEARS that correction; ids not sent are left untouched." } }, "required": [ "id", "names" ], "additionalProperties": false, "examples": [ { "id": "e_example", "names": {} } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." }, "speaker_names": { "description": "Speaker ID to display name.", "type": "object", "additionalProperties": { "type": "string", "description": "Display name for this speaker." } } }, "required": [ "ok", "speaker_names" ], "additionalProperties": false, "examples": [ { "ok": true, "speaker_names": {} } ] } ``` --- # Update meeting Update a meeting by ID. Omitted fields stay unchanged; use unset to remove fields and expected to prevent overwriting a concurrent change. POST https://api.brigg.app/v1/operations/meetings.UpdateMeeting ## Access & visibility Allow `meetings.UpdateMeeting` on your API key. Resource read permissions: `core:Meeting`. Resource write permissions: `core:Meeting`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:Meeting` record. Find it with [meetings.ListMeetings](/developers/reference/meetings/ListMeetings). Use the record's top-level `id`, not a business field or account ID. | | `data` | [Meeting](#meeting-request-data) | No | The fields to set. | | `unset` | array of string | No | Keys of `data` to remove. Each item: `"title"`, `"started_by"`, `"start_time"`, `"end_time"`, `"status"`, `"language"`, `"participants"`, `"calendar_event_id"`, `"sharing_external"`, `"call_direction"`, `"call_outcome"`, `"call_duration_ms"`, `"counterpart_e164"`, `"call_forwarded"`, `"conference_url"`, `"contact_refs"`, `"company_refs"`, `"related_meetings"`, `"agenda"`, `"meeting_type"`, `"gist"`, `"summary_bullets"`, `"summary"`, `"summary_language"`, `"custom_summary"`. | | `expected` | [object](#request-expected) | No | Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {"$absent":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource. | ### Meeting · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string | No | Meeting title. May be absent when no title has been supplied. | | `start_time` | number | No | Meeting start time in Unix milliseconds. Use a number, not an ISO date string, when filtering this field. | | `end_time` | number | No | Meeting end time in Unix milliseconds. May be absent before the meeting ends. | | `language` | string | No | Language recorded for the meeting, such as en or no. It may differ from summary_language. | | `participants` | array of string or [MeetingParticipant](#meetingparticipant-request-data-participants) | No | Attendee names or objects containing a name, email and optional Person record reference. | | `contact_refs` | array of string | No | Linked Person record IDs. Use has to filter for a particular contact. | | `company_refs` | array of string | No | Linked Company record IDs. Use has to filter for a particular company. | | `related_meetings` | array of string | No | IDs of related Meeting records. Each related record has its own access rules. | | `agenda` | array of [object](#request-data-agenda) | No | Two-level agenda: topics and optional subtopics. Status tracks how much of each topic was covered. | | `meeting_type` | string | No | Descriptive meeting category in the meeting's language. Free text, not a fixed enum. | ### MeetingParticipant · request.data.participants[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | No | Display name. | | `email` | string | No | Email address. | | `ref` | string | No | Person record ID for this attendee, when matched to a customer contact. It is not a workspace account ID. | ### request.data.agenda[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | | `subtopics` | array of [object](#request-data-agenda-subtopics) | No | Second-level discussion topics; no deeper nesting is supported. | ### request.data.agenda[].subtopics[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | ### request.expected | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string or [object](#request-expected-title) | No | Commit only if the previous title value matches; use $absent to require that this field is missing. | | `started_by` | string or [object](#request-expected-started-by) | No | Commit only if the previous started_by value matches; use $absent to require that this field is missing. | | `start_time` | number or [object](#request-expected-start-time) | No | Commit only if the previous start_time value matches; use $absent to require that this field is missing. | | `end_time` | number or [object](#request-expected-end-time) | No | Commit only if the previous end_time value matches; use $absent to require that this field is missing. | | `status` | string or [object](#request-expected-status) | No | Commit only if the previous status value matches; use $absent to require that this field is missing. | | `language` | string or [object](#request-expected-language) | No | Commit only if the previous language value matches; use $absent to require that this field is missing. | | `participants` | array of string or [MeetingParticipant](#meetingparticipant-request-expected-participants) or [object](#request-expected-participants) | No | Commit only if the previous participants value matches; use $absent to require that this field is missing. | | `calendar_event_id` | string or [object](#request-expected-calendar-event-id) | No | Commit only if the previous calendar_event_id value matches; use $absent to require that this field is missing. | | `sharing_external` | boolean or [object](#request-expected-sharing-external) | No | Commit only if the previous sharing_external value matches; use $absent to require that this field is missing. | | `call_direction` | string or [object](#request-expected-call-direction) | No | Commit only if the previous call_direction value matches; use $absent to require that this field is missing. | | `call_outcome` | string or [object](#request-expected-call-outcome) | No | Commit only if the previous call_outcome value matches; use $absent to require that this field is missing. | | `call_duration_ms` | number or [object](#request-expected-call-duration-ms) | No | Commit only if the previous call_duration_ms value matches; use $absent to require that this field is missing. | | `counterpart_e164` | string or [object](#request-expected-counterpart-e164) | No | Commit only if the previous counterpart_e164 value matches; use $absent to require that this field is missing. | | `call_forwarded` | boolean or [object](#request-expected-call-forwarded) | No | Commit only if the previous call_forwarded value matches; use $absent to require that this field is missing. | | `conference_url` | string or [object](#request-expected-conference-url) | No | Commit only if the previous conference_url value matches; use $absent to require that this field is missing. | | `contact_refs` | array of string or [object](#request-expected-contact-refs) | No | Commit only if the previous contact_refs value matches; use $absent to require that this field is missing. | | `company_refs` | array of string or [object](#request-expected-company-refs) | No | Commit only if the previous company_refs value matches; use $absent to require that this field is missing. | | `related_meetings` | array of string or [object](#request-expected-related-meetings) | No | Commit only if the previous related_meetings value matches; use $absent to require that this field is missing. | | `agenda` | array of [object](#request-expected-agenda) or [object](#request-expected-agenda) | No | Commit only if the previous agenda value matches; use $absent to require that this field is missing. | | `meeting_type` | string or [object](#request-expected-meeting-type) | No | Commit only if the previous meeting_type value matches; use $absent to require that this field is missing. | | `gist` | string or [object](#request-expected-gist) | No | Commit only if the previous gist value matches; use $absent to require that this field is missing. | | `summary_bullets` | array of string or [object](#request-expected-summary-bullets) | No | Commit only if the previous summary_bullets value matches; use $absent to require that this field is missing. | | `summary` | string or [object](#request-expected-summary) | No | Commit only if the previous summary value matches; use $absent to require that this field is missing. | | `summary_language` | string or [object](#request-expected-summary-language) | No | Commit only if the previous summary_language value matches; use $absent to require that this field is missing. | | `custom_summary` | [object (2 variants)](#request-expected-custom-summary) | No | Commit only if the previous custom_summary value matches; use $absent to require that this field is missing. | ### request.expected.title | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.started_by | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.start_time | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.end_time | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.status | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.language | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.participants | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### MeetingParticipant · request.expected.participants[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | No | Display name. | | `email` | string | No | Email address. | | `ref` | string | No | Person record ID for this attendee, when matched to a customer contact. It is not a workspace account ID. | ### request.expected.calendar_event_id | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.sharing_external | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.call_direction | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.call_outcome | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.call_duration_ms | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.counterpart_e164 | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.call_forwarded | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.conference_url | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.contact_refs | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.company_refs | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.related_meetings | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.agenda | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.agenda[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | | `subtopics` | array of [object](#request-expected-agenda-subtopics) | No | Second-level discussion topics; no deeper nesting is supported. | ### request.expected.agenda[].subtopics[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | ### request.expected.meeting_type | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.gist | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.summary_bullets | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.summary | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.summary_language | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.custom_summary #### Variant 1 | Field | Type | Required | Description | | --- | --- | --- | --- | | `example` | string | No | Example output illustrating the desired summary style. | | `instructions` | string | No | Instructions to follow when generating the summary. | #### $absent = true | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ## Update without losing changes Send only the business fields you want to change in `data`; omitted fields stay unchanged. Use `unset` to remove an optional field. Setting a field to null is a different action and is allowed only when its schema permits null. Use `expected` for a conditional update: supply the values you last read for the fields whose concurrent changes would matter. `{"$absent": true}` expects a missing field. A conflict means you must read the record again and decide how to reconcile the change. Keep the same idempotency key when retrying the original action; use a new key for a revised action. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. An ended meeting is not necessarily summarized yet. Summary fields can be absent while work is pending or when no summary is available; this response does not expose the reason. Transcript text and recording URLs are not part of this model. Personal notes are a separate resource and retain the acting member's access rules. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [MeetingRecord](#meetingrecord-response-item) | Yes | The requested record, including its metadata and data fields. | ### MeetingRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Meeting record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Meeting](#meeting-response-item-data) | Yes | The record's fields. | ### Meeting · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string | No | Meeting title. May be absent when no title has been supplied. | | `started_by` | string | No | Host account ID. This is the member identity that owns the meeting; created_by is separate record provenance. | | `start_time` | number | Yes | Meeting start time in Unix milliseconds. Use a number, not an ISO date string, when filtering this field. | | `end_time` | number | No | Meeting end time in Unix milliseconds. May be absent before the meeting ends. | | `status` | string | Yes | Meeting lifecycle state, including live, paused and ended. This is an open string, not a closed enum; tolerate additional states. | | `language` | string | No | Language recorded for the meeting, such as en or no. It may differ from summary_language. | | `participants` | array of string or [MeetingParticipant](#meetingparticipant-response-item-data-participants) | No | Attendee names or objects containing a name, email and optional Person record reference. | | `calendar_event_id` | string | No | ID of a `core:CalendarEvent` record. Find it with [meetings.ListCalendarEvents](/developers/reference/meetings/ListCalendarEvents) and use the top-level `id`. This is not an account ID or a display name. | | `sharing_external` | boolean | No | Whether external attendees were identified when the meeting was prepared. This is not permission to share the meeting externally; absence means this fact was not recorded. | | `call_direction` | string | No | Phone call direction, currently inbound or outbound. Absent for meetings without phone-call metadata. | | `call_outcome` | string | No | How a phone call ended, including completed, no_answer, busy, declined, canceled or failed. This is an open string. | | `call_duration_ms` | number | No | Recorded phone-call duration in milliseconds. | | `counterpart_e164` | string | No | Other party's phone number in international E.164 format, such as +4721001234. | | `call_forwarded` | boolean | No | Whether the incoming call was forwarded from another phone number. | | `conference_url` | string | No | Conference link from the calendar invitation, when one is available. | | `contact_refs` | array of string | No | Linked Person record IDs. Use has to filter for a particular contact. | | `company_refs` | array of string | No | Linked Company record IDs. Use has to filter for a particular company. | | `related_meetings` | array of string | No | IDs of related Meeting records. Each related record has its own access rules. | | `agenda` | array of [object](#response-item-data-agenda) | No | Two-level agenda: topics and optional subtopics. Status tracks how much of each topic was covered. | | `meeting_type` | string | No | Descriptive meeting category in the meeting's language. Free text, not a fixed enum. | | `gist` | string | No | One- or two-line takeaway from the meeting. | | `summary_bullets` | array of string | No | Key points extracted from the meeting. | | `summary` | string | No | Full meeting summary formatted as Markdown. | | `summary_language` | string | No | Language of the generated summary, such as en or no. | | `custom_summary` | [object](#response-item-data-custom-summary) | No | Instructions and optional example used to generate a custom summary. This is configuration, not the generated summary. | ### MeetingParticipant · response.item.data.participants[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | No | Display name. | | `email` | string | No | Email address. | | `ref` | string | No | Person record ID for this attendee, when matched to a customer contact. It is not a workspace account ID. | ### response.item.data.agenda[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | | `subtopics` | array of [object](#response-item-data-agenda-subtopics) | No | Second-level discussion topics; no deeper nesting is supported. | ### response.item.data.agenda[].subtopics[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | ### response.item.data.custom_summary | Field | Type | Required | Description | | --- | --- | --- | --- | | `example` | string | No | Example output illustrating the desired summary style. | | `instructions` | string | No | Instructions to follow when generating the summary. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `conflict` | A supplied expected value no longer matches. Read the record again before deciding whether to retry. | ## Next steps - [List meetings](/developers/reference/meetings/ListMeetings) - [Get meeting](/developers/reference/meetings/GetMeeting) - [Create meeting](/developers/reference/meetings/CreateMeeting) - [Upsert meeting](/developers/reference/meetings/UpsertMeeting) - [Delete meeting](/developers/reference/meetings/DeleteMeeting) - [Read personal meeting notes](/developers/reference/meetings/ListMeetingNotes) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.UpdateMeeting' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_meeting_example", "data": { "title": "Northstar · pilot kickoff" } }' ``` #### TypeScript ```typescript 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.UpdateMeeting", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_meeting_example", "data": { "title": "Northstar · pilot 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_example", "data": { "title": "Northstar · pilot kickoff" } } request = Request( "https://api.brigg.app/v1/operations/meetings.UpdateMeeting", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_meeting_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "title": "Northstar · pilot kickoff", "start_time": 1791277200000, "end_time": 1791279900000, "status": "ended", "started_by": "a_jamie", "participants": [ { "name": "Jamie Lee", "email": "jamie@example.com" }, { "name": "Alex Morgan", "email": "alex@example.org", "ref": "e_person_alex" } ], "company_refs": [ "e_company_northstar" ], "gist": "The team agreed to begin the pilot on 19 October.", "summary_bullets": [ "Alex will send the source data by Friday.", "Jamie will prepare the pilot workspace." ], "summary": "## Decisions\nStart the pilot on 19 October.\n\n## Next steps\n- Alex: send source data by Friday.\n- Jamie: prepare the workspace.", "summary_language": "en" } } } ``` ### Update only if unchanged Use a value you actually read. A concurrent change refuses the write with 409 conflict. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.UpdateMeeting' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_meeting_example", "data": { "title": "Northstar · pilot kickoff" }, "expected": { "title": "Northstar · project kickoff" } }' ``` #### TypeScript ```typescript 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.UpdateMeeting", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_meeting_example", "data": { "title": "Northstar · pilot kickoff" }, "expected": { "title": "Northstar · project 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_example", "data": { "title": "Northstar · pilot kickoff" }, "expected": { "title": "Northstar · project kickoff" } } request = Request( "https://api.brigg.app/v1/operations/meetings.UpdateMeeting", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_meeting_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "title": "Northstar · pilot kickoff", "start_time": 1791277200000, "end_time": 1791279900000, "status": "ended", "started_by": "a_jamie", "participants": [ { "name": "Jamie Lee", "email": "jamie@example.com" }, { "name": "Alex Morgan", "email": "alex@example.org", "ref": "e_person_alex" } ], "company_refs": [ "e_company_northstar" ], "gist": "The team agreed to begin the pilot on 19 October.", "summary_bullets": [ "Alex will send the source data by Friday.", "Jamie will prepare the pilot workspace." ], "summary": "## Decisions\nStart the pilot on 19 October.\n\n## Next steps\n- Alex: send source data by Friday.\n- Jamie: prepare the workspace.", "summary_language": "en" } } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:Meeting` record. Find it with [meetings.ListMeetings](/developers/reference/meetings/ListMeetings). Use the record's top-level `id`, not a business field or account ID." }, "data": { "type": "object", "properties": { "title": { "type": "string", "description": "Meeting title. May be absent when no title has been supplied." }, "start_time": { "type": "number", "description": "Meeting start time in Unix milliseconds. Use a number, not an ISO date string, when filtering this field." }, "end_time": { "type": "number", "description": "Meeting end time in Unix milliseconds. May be absent before the meeting ends." }, "language": { "type": "string", "description": "Language recorded for the meeting, such as en or no. It may differ from summary_language." }, "participants": { "type": "array", "items": { "title": "MeetingParticipant", "anyOf": [ { "type": "string", "title": "MeetingParticipant" }, { "type": "object", "properties": { "name": { "type": "string", "description": "Display name." }, "email": { "type": "string", "description": "Email address." }, "ref": { "type": "string", "description": "Person record ID for this attendee, when matched to a customer contact. It is not a workspace account ID." } }, "required": [], "additionalProperties": false, "title": "MeetingParticipant" } ] }, "description": "Attendee names or objects containing a name, email and optional Person record reference." }, "contact_refs": { "type": "array", "items": { "type": "string", "description": "id of a core:Person" }, "description": "Linked Person record IDs. Use has to filter for a particular contact." }, "company_refs": { "type": "array", "items": { "type": "string", "description": "id of a core:Company" }, "description": "Linked Company record IDs. Use has to filter for a particular company." }, "related_meetings": { "type": "array", "items": { "type": "string", "description": "id of a core:Meeting" }, "description": "IDs of related Meeting records. Each related record has its own access rules." }, "agenda": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." }, "subtopics": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." } }, "additionalProperties": false }, "description": "Second-level discussion topics; no deeper nesting is supported." } }, "additionalProperties": false }, "description": "Two-level agenda: topics and optional subtopics. Status tracks how much of each topic was covered." }, "meeting_type": { "type": "string", "description": "Descriptive meeting category in the meeting's language. Free text, not a fixed enum." } }, "required": [], "additionalProperties": false, "description": "The fields to set.", "title": "Meeting" }, "unset": { "type": "array", "items": { "type": "string", "enum": [ "title", "started_by", "start_time", "end_time", "status", "language", "participants", "calendar_event_id", "sharing_external", "call_direction", "call_outcome", "call_duration_ms", "counterpart_e164", "call_forwarded", "conference_url", "contact_refs", "company_refs", "related_meetings", "agenda", "meeting_type", "gist", "summary_bullets", "summary", "summary_language", "custom_summary" ] }, "description": "Keys of `data` to remove." }, "expected": { "type": "object", "description": "Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {\"$absent\":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource.", "additionalProperties": false, "properties": { "title": { "description": "Commit only if the previous title value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Meeting title. May be absent when no title has been supplied." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "started_by": { "description": "Commit only if the previous started_by value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Host account ID. This is the member identity that owns the meeting; created_by is separate record provenance." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "start_time": { "description": "Commit only if the previous start_time value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "number", "description": "Meeting start time in Unix milliseconds. Use a number, not an ISO date string, when filtering this field." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "end_time": { "description": "Commit only if the previous end_time value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "number", "description": "Meeting end time in Unix milliseconds. May be absent before the meeting ends." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "status": { "description": "Commit only if the previous status value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Meeting lifecycle state, including live, paused and ended. This is an open string, not a closed enum; tolerate additional states." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "language": { "description": "Commit only if the previous language value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Language recorded for the meeting, such as en or no. It may differ from summary_language." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "participants": { "description": "Commit only if the previous participants value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "title": "MeetingParticipant", "anyOf": [ { "type": "string", "title": "MeetingParticipant" }, { "type": "object", "properties": { "name": { "type": "string", "description": "Display name." }, "email": { "type": "string", "description": "Email address." }, "ref": { "type": "string", "description": "Person record ID for this attendee, when matched to a customer contact. It is not a workspace account ID." } }, "required": [], "additionalProperties": false, "title": "MeetingParticipant" } ] }, "description": "Attendee names or objects containing a name, email and optional Person record reference." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "calendar_event_id": { "description": "Commit only if the previous calendar_event_id value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "ID of a `core:CalendarEvent` record. Find it with [meetings.ListCalendarEvents](/developers/reference/meetings/ListCalendarEvents) and use the top-level `id`. This is not an account ID or a display name." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "sharing_external": { "description": "Commit only if the previous sharing_external value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "boolean", "description": "Whether external attendees were identified when the meeting was prepared. This is not permission to share the meeting externally; absence means this fact was not recorded." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "call_direction": { "description": "Commit only if the previous call_direction value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Phone call direction, currently inbound or outbound. Absent for meetings without phone-call metadata." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "call_outcome": { "description": "Commit only if the previous call_outcome value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "How a phone call ended, including completed, no_answer, busy, declined, canceled or failed. This is an open string." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "call_duration_ms": { "description": "Commit only if the previous call_duration_ms value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "number", "description": "Recorded phone-call duration in milliseconds." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "counterpart_e164": { "description": "Commit only if the previous counterpart_e164 value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Other party's phone number in international E.164 format, such as +4721001234." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "call_forwarded": { "description": "Commit only if the previous call_forwarded value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "boolean", "description": "Whether the incoming call was forwarded from another phone number." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "conference_url": { "description": "Commit only if the previous conference_url value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Conference link from the calendar invitation, when one is available." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "contact_refs": { "description": "Commit only if the previous contact_refs value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "type": "string", "description": "id of a core:Person" }, "description": "Linked Person record IDs. Use has to filter for a particular contact." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "company_refs": { "description": "Commit only if the previous company_refs value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "type": "string", "description": "id of a core:Company" }, "description": "Linked Company record IDs. Use has to filter for a particular company." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "related_meetings": { "description": "Commit only if the previous related_meetings value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "type": "string", "description": "id of a core:Meeting" }, "description": "IDs of related Meeting records. Each related record has its own access rules." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "agenda": { "description": "Commit only if the previous agenda value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." }, "subtopics": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." } }, "additionalProperties": false }, "description": "Second-level discussion topics; no deeper nesting is supported." } }, "additionalProperties": false }, "description": "Two-level agenda: topics and optional subtopics. Status tracks how much of each topic was covered." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "meeting_type": { "description": "Commit only if the previous meeting_type value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Descriptive meeting category in the meeting's language. Free text, not a fixed enum." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "gist": { "description": "Commit only if the previous gist value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "One- or two-line takeaway from the meeting." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "summary_bullets": { "description": "Commit only if the previous summary_bullets value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "type": "string" }, "description": "Key points extracted from the meeting." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "summary": { "description": "Commit only if the previous summary value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Full meeting summary formatted as Markdown." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "summary_language": { "description": "Commit only if the previous summary_language value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Language of the generated summary, such as en or no." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "custom_summary": { "description": "Commit only if the previous custom_summary value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "object", "properties": { "example": { "type": "string", "description": "Example output illustrating the desired summary style." }, "instructions": { "type": "string", "description": "Instructions to follow when generating the summary." } }, "additionalProperties": false, "description": "Instructions and optional example used to generate a custom summary. This is configuration, not the generated summary." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] } } } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_meeting_example", "data": { "title": "Northstar · pilot kickoff" } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:Meeting record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "title": { "type": "string", "description": "Meeting title. May be absent when no title has been supplied." }, "started_by": { "type": "string", "description": "Host account ID. This is the member identity that owns the meeting; created_by is separate record provenance." }, "start_time": { "type": "number", "description": "Meeting start time in Unix milliseconds. Use a number, not an ISO date string, when filtering this field." }, "end_time": { "type": "number", "description": "Meeting end time in Unix milliseconds. May be absent before the meeting ends." }, "status": { "type": "string", "description": "Meeting lifecycle state, including live, paused and ended. This is an open string, not a closed enum; tolerate additional states." }, "language": { "type": "string", "description": "Language recorded for the meeting, such as en or no. It may differ from summary_language." }, "participants": { "type": "array", "items": { "title": "MeetingParticipant", "anyOf": [ { "type": "string", "title": "MeetingParticipant" }, { "type": "object", "properties": { "name": { "type": "string", "description": "Display name." }, "email": { "type": "string", "description": "Email address." }, "ref": { "type": "string", "description": "Person record ID for this attendee, when matched to a customer contact. It is not a workspace account ID." } }, "required": [], "additionalProperties": false, "title": "MeetingParticipant" } ] }, "description": "Attendee names or objects containing a name, email and optional Person record reference." }, "calendar_event_id": { "type": "string", "description": "ID of a `core:CalendarEvent` record. Find it with [meetings.ListCalendarEvents](/developers/reference/meetings/ListCalendarEvents) and use the top-level `id`. This is not an account ID or a display name." }, "sharing_external": { "type": "boolean", "description": "Whether external attendees were identified when the meeting was prepared. This is not permission to share the meeting externally; absence means this fact was not recorded." }, "call_direction": { "type": "string", "description": "Phone call direction, currently inbound or outbound. Absent for meetings without phone-call metadata." }, "call_outcome": { "type": "string", "description": "How a phone call ended, including completed, no_answer, busy, declined, canceled or failed. This is an open string." }, "call_duration_ms": { "type": "number", "description": "Recorded phone-call duration in milliseconds." }, "counterpart_e164": { "type": "string", "description": "Other party's phone number in international E.164 format, such as +4721001234." }, "call_forwarded": { "type": "boolean", "description": "Whether the incoming call was forwarded from another phone number." }, "conference_url": { "type": "string", "description": "Conference link from the calendar invitation, when one is available." }, "contact_refs": { "type": "array", "items": { "type": "string", "description": "id of a core:Person" }, "description": "Linked Person record IDs. Use has to filter for a particular contact." }, "company_refs": { "type": "array", "items": { "type": "string", "description": "id of a core:Company" }, "description": "Linked Company record IDs. Use has to filter for a particular company." }, "related_meetings": { "type": "array", "items": { "type": "string", "description": "id of a core:Meeting" }, "description": "IDs of related Meeting records. Each related record has its own access rules." }, "agenda": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." }, "subtopics": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." } }, "additionalProperties": false }, "description": "Second-level discussion topics; no deeper nesting is supported." } }, "additionalProperties": false }, "description": "Two-level agenda: topics and optional subtopics. Status tracks how much of each topic was covered." }, "meeting_type": { "type": "string", "description": "Descriptive meeting category in the meeting's language. Free text, not a fixed enum." }, "gist": { "type": "string", "description": "One- or two-line takeaway from the meeting." }, "summary_bullets": { "type": "array", "items": { "type": "string" }, "description": "Key points extracted from the meeting." }, "summary": { "type": "string", "description": "Full meeting summary formatted as Markdown." }, "summary_language": { "type": "string", "description": "Language of the generated summary, such as en or no." }, "custom_summary": { "type": "object", "properties": { "example": { "type": "string", "description": "Example output illustrating the desired summary style." }, "instructions": { "type": "string", "description": "Instructions to follow when generating the summary." } }, "additionalProperties": false, "description": "Instructions and optional example used to generate a custom summary. This is configuration, not the generated summary." } }, "required": [ "start_time", "status" ], "additionalProperties": false, "description": "The record's fields.", "title": "Meeting" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "MeetingRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_meeting_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "title": "Northstar · pilot kickoff", "start_time": 1791277200000, "end_time": 1791279900000, "status": "ended", "started_by": "a_jamie", "participants": [ { "name": "Jamie Lee", "email": "jamie@example.com" }, { "name": "Alex Morgan", "email": "alex@example.org", "ref": "e_person_alex" } ], "company_refs": [ "e_company_northstar" ], "gist": "The team agreed to begin the pilot on 19 October.", "summary_bullets": [ "Alex will send the source data by Friday.", "Jamie will prepare the pilot workspace." ], "summary": "## Decisions\nStart the pilot on 19 October.\n\n## Next steps\n- Alex: send source data by Friday.\n- Jamie: prepare the workspace.", "summary_language": "en" } } } ] } ``` --- # Upsert meeting Create or update a meeting by a permanent external reference. Matching is exact within the workspace, resource type and ownership scope. Supplied fields replace their values; omitted fields stay unchanged. Deleted records are not recreated. POST https://api.brigg.app/v1/operations/meetings.UpsertMeeting ## Access & visibility Allow `meetings.UpsertMeeting` on your API key. Resource read permissions: `core:Meeting`. Resource write permissions: `core:Meeting`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `data` | [Meeting](#meeting-request-data) | Yes | The record's fields. | | `private` | boolean | No | Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance. | | `external_ref` | [object](#request-external-ref) | Yes | Permanent, case-sensitive source identity within this workspace, resource type and private/workspace scope. It is independent of API key rotation and retry receipt expiry. | ### Meeting · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string | No | Meeting title. May be absent when no title has been supplied. | | `start_time` | number | Yes | Meeting start time in Unix milliseconds. Use a number, not an ISO date string, when filtering this field. | | `end_time` | number | No | Meeting end time in Unix milliseconds. May be absent before the meeting ends. | | `language` | string | No | Language recorded for the meeting, such as en or no. It may differ from summary_language. | | `participants` | array of string or [MeetingParticipant](#meetingparticipant-request-data-participants) | No | Attendee names or objects containing a name, email and optional Person record reference. | | `contact_refs` | array of string | No | Linked Person record IDs. Use has to filter for a particular contact. | | `company_refs` | array of string | No | Linked Company record IDs. Use has to filter for a particular company. | | `related_meetings` | array of string | No | IDs of related Meeting records. Each related record has its own access rules. | | `agenda` | array of [object](#request-data-agenda) | No | Two-level agenda: topics and optional subtopics. Status tracks how much of each topic was covered. | | `meeting_type` | string | No | Descriptive meeting category in the meeting's language. Free text, not a fixed enum. | ### MeetingParticipant · request.data.participants[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | No | Display name. | | `email` | string | No | Email address. | | `ref` | string | No | Person record ID for this attendee, when matched to a customer contact. It is not a workspace account ID. | ### request.data.agenda[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | | `subtopics` | array of [object](#request-data-agenda-subtopics) | No | Second-level discussion topics; no deeper nesting is supported. | ### request.data.agenda[].subtopics[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | ### request.external_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `namespace` | string | Yes | A stable name for the source system, such as crm-production. At least 1 character. | | `id` | string | Yes | The record ID in that source system. At least 1 character. | ## Sync with a permanent external reference Choose a stable `external_ref.namespace` for your source system and put its record ID in `external_ref.id`. Matching is case-sensitive and scoped to this workspace, resource type and private/workspace ownership. The reference survives API key replacement and the 30-day retry receipt window. It does not match records by email or name. Send the required create fields each time. A missing reference creates a record; an existing reference updates only supplied fields and preserves everything else. `created` tells you which happened. Use the same idempotency key when retrying a lost response and a new key for a later source change. Concurrent calls cannot create duplicate records. A deleted or inaccessible match is refused; the operation does not restore it or make a replacement. Use the returned `item.id` with the regular update operation when you need `unset` or a conditional `expected` edit. Changing `private` chooses a different ownership scope; it does not transfer an existing record. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. An ended meeting is not necessarily summarized yet. Summary fields can be absent while work is pending or when no summary is available; this response does not expose the reason. Transcript text and recording URLs are not part of this model. Personal notes are a separate resource and retain the acting member's access rules. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [MeetingRecord](#meetingrecord-response-item) | Yes | The requested record, including its metadata and data fields. | | `created` | boolean | Yes | True when this external reference created a record; false when it matched an existing record. | ### MeetingRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Meeting record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Meeting](#meeting-response-item-data) | Yes | The record's fields. | ### Meeting · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string | No | Meeting title. May be absent when no title has been supplied. | | `started_by` | string | No | Host account ID. This is the member identity that owns the meeting; created_by is separate record provenance. | | `start_time` | number | Yes | Meeting start time in Unix milliseconds. Use a number, not an ISO date string, when filtering this field. | | `end_time` | number | No | Meeting end time in Unix milliseconds. May be absent before the meeting ends. | | `status` | string | Yes | Meeting lifecycle state, including live, paused and ended. This is an open string, not a closed enum; tolerate additional states. | | `language` | string | No | Language recorded for the meeting, such as en or no. It may differ from summary_language. | | `participants` | array of string or [MeetingParticipant](#meetingparticipant-response-item-data-participants) | No | Attendee names or objects containing a name, email and optional Person record reference. | | `calendar_event_id` | string | No | ID of a `core:CalendarEvent` record. Find it with [meetings.ListCalendarEvents](/developers/reference/meetings/ListCalendarEvents) and use the top-level `id`. This is not an account ID or a display name. | | `sharing_external` | boolean | No | Whether external attendees were identified when the meeting was prepared. This is not permission to share the meeting externally; absence means this fact was not recorded. | | `call_direction` | string | No | Phone call direction, currently inbound or outbound. Absent for meetings without phone-call metadata. | | `call_outcome` | string | No | How a phone call ended, including completed, no_answer, busy, declined, canceled or failed. This is an open string. | | `call_duration_ms` | number | No | Recorded phone-call duration in milliseconds. | | `counterpart_e164` | string | No | Other party's phone number in international E.164 format, such as +4721001234. | | `call_forwarded` | boolean | No | Whether the incoming call was forwarded from another phone number. | | `conference_url` | string | No | Conference link from the calendar invitation, when one is available. | | `contact_refs` | array of string | No | Linked Person record IDs. Use has to filter for a particular contact. | | `company_refs` | array of string | No | Linked Company record IDs. Use has to filter for a particular company. | | `related_meetings` | array of string | No | IDs of related Meeting records. Each related record has its own access rules. | | `agenda` | array of [object](#response-item-data-agenda) | No | Two-level agenda: topics and optional subtopics. Status tracks how much of each topic was covered. | | `meeting_type` | string | No | Descriptive meeting category in the meeting's language. Free text, not a fixed enum. | | `gist` | string | No | One- or two-line takeaway from the meeting. | | `summary_bullets` | array of string | No | Key points extracted from the meeting. | | `summary` | string | No | Full meeting summary formatted as Markdown. | | `summary_language` | string | No | Language of the generated summary, such as en or no. | | `custom_summary` | [object](#response-item-data-custom-summary) | No | Instructions and optional example used to generate a custom summary. This is configuration, not the generated summary. | ### MeetingParticipant · response.item.data.participants[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | No | Display name. | | `email` | string | No | Email address. | | `ref` | string | No | Person record ID for this attendee, when matched to a customer contact. It is not a workspace account ID. | ### response.item.data.agenda[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | | `subtopics` | array of [object](#response-item-data-agenda-subtopics) | No | Second-level discussion topics; no deeper nesting is supported. | ### response.item.data.agenda[].subtopics[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | ### response.item.data.custom_summary | Field | Type | Required | Description | | --- | --- | --- | --- | | `example` | string | No | Example output illustrating the desired summary style. | | `instructions` | string | No | Instructions to follow when generating the summary. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List meetings](/developers/reference/meetings/ListMeetings) - [Get meeting](/developers/reference/meetings/GetMeeting) - [Create meeting](/developers/reference/meetings/CreateMeeting) - [Update meeting](/developers/reference/meetings/UpdateMeeting) - [Delete meeting](/developers/reference/meetings/DeleteMeeting) - [Read personal meeting notes](/developers/reference/meetings/ListMeetingNotes) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### First sync Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.UpsertMeeting' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "title": "Northstar · project kickoff", "start_time": 1791277200000, "end_time": 1791279900000, "participants": [ { "name": "Jamie Lee", "email": "jamie@example.com" }, { "name": "Alex Morgan", "email": "alex@example.org", "ref": "e_person_alex" } ], "company_refs": [ "e_company_northstar" ] } }' ``` #### TypeScript ```typescript 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.UpsertMeeting", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "title": "Northstar · project kickoff", "start_time": 1791277200000, "end_time": 1791279900000, "participants": [ { "name": "Jamie Lee", "email": "jamie@example.com" }, { "name": "Alex Morgan", "email": "alex@example.org", "ref": "e_person_alex" } ], "company_refs": [ "e_company_northstar" ] } }), }); 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 = { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "title": "Northstar · project kickoff", "start_time": 1791277200000, "end_time": 1791279900000, "participants": [ { "name": "Jamie Lee", "email": "jamie@example.com" }, { "name": "Alex Morgan", "email": "alex@example.org", "ref": "e_person_alex" } ], "company_refs": [ "e_company_northstar" ] } } request = Request( "https://api.brigg.app/v1/operations/meetings.UpsertMeeting", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_meeting_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "title": "Northstar · project kickoff", "start_time": 1791277200000, "end_time": 1791279900000, "status": "ended", "started_by": "a_jamie", "participants": [ { "name": "Jamie Lee", "email": "jamie@example.com" }, { "name": "Alex Morgan", "email": "alex@example.org", "ref": "e_person_alex" } ], "company_refs": [ "e_company_northstar" ], "gist": "The team agreed to begin the pilot on 19 October.", "summary_bullets": [ "Alex will send the source data by Friday.", "Jamie will prepare the pilot workspace." ], "summary": "## Decisions\nStart the pilot on 19 October.\n\n## Next steps\n- Alex: send source data by Friday.\n- Jamie: prepare the workspace.", "summary_language": "en" } }, "created": true } ``` ### Later sync The same external reference returns the same record ID. Use a new idempotency key for a later source change. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.UpsertMeeting' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "title": "Northstar · project kickoff", "start_time": 1791277200000, "end_time": 1791279900000, "participants": [ { "name": "Jamie Lee", "email": "jamie@example.com" }, { "name": "Alex Morgan", "email": "alex@example.org", "ref": "e_person_alex" } ], "company_refs": [ "e_company_northstar" ] } }' ``` #### TypeScript ```typescript 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.UpsertMeeting", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "title": "Northstar · project kickoff", "start_time": 1791277200000, "end_time": 1791279900000, "participants": [ { "name": "Jamie Lee", "email": "jamie@example.com" }, { "name": "Alex Morgan", "email": "alex@example.org", "ref": "e_person_alex" } ], "company_refs": [ "e_company_northstar" ] } }), }); 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 = { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "title": "Northstar · project kickoff", "start_time": 1791277200000, "end_time": 1791279900000, "participants": [ { "name": "Jamie Lee", "email": "jamie@example.com" }, { "name": "Alex Morgan", "email": "alex@example.org", "ref": "e_person_alex" } ], "company_refs": [ "e_company_northstar" ] } } request = Request( "https://api.brigg.app/v1/operations/meetings.UpsertMeeting", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_meeting_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "title": "Northstar · project kickoff", "start_time": 1791277200000, "end_time": 1791279900000, "status": "ended", "started_by": "a_jamie", "participants": [ { "name": "Jamie Lee", "email": "jamie@example.com" }, { "name": "Alex Morgan", "email": "alex@example.org", "ref": "e_person_alex" } ], "company_refs": [ "e_company_northstar" ], "gist": "The team agreed to begin the pilot on 19 October.", "summary_bullets": [ "Alex will send the source data by Friday.", "Jamie will prepare the pilot workspace." ], "summary": "## Decisions\nStart the pilot on 19 October.\n\n## Next steps\n- Alex: send source data by Friday.\n- Jamie: prepare the workspace.", "summary_language": "en" } }, "created": false } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "data": { "type": "object", "properties": { "title": { "type": "string", "description": "Meeting title. May be absent when no title has been supplied." }, "start_time": { "type": "number", "description": "Meeting start time in Unix milliseconds. Use a number, not an ISO date string, when filtering this field." }, "end_time": { "type": "number", "description": "Meeting end time in Unix milliseconds. May be absent before the meeting ends." }, "language": { "type": "string", "description": "Language recorded for the meeting, such as en or no. It may differ from summary_language." }, "participants": { "type": "array", "items": { "title": "MeetingParticipant", "anyOf": [ { "type": "string", "title": "MeetingParticipant" }, { "type": "object", "properties": { "name": { "type": "string", "description": "Display name." }, "email": { "type": "string", "description": "Email address." }, "ref": { "type": "string", "description": "Person record ID for this attendee, when matched to a customer contact. It is not a workspace account ID." } }, "required": [], "additionalProperties": false, "title": "MeetingParticipant" } ] }, "description": "Attendee names or objects containing a name, email and optional Person record reference." }, "contact_refs": { "type": "array", "items": { "type": "string", "description": "id of a core:Person" }, "description": "Linked Person record IDs. Use has to filter for a particular contact." }, "company_refs": { "type": "array", "items": { "type": "string", "description": "id of a core:Company" }, "description": "Linked Company record IDs. Use has to filter for a particular company." }, "related_meetings": { "type": "array", "items": { "type": "string", "description": "id of a core:Meeting" }, "description": "IDs of related Meeting records. Each related record has its own access rules." }, "agenda": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." }, "subtopics": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." } }, "additionalProperties": false }, "description": "Second-level discussion topics; no deeper nesting is supported." } }, "additionalProperties": false }, "description": "Two-level agenda: topics and optional subtopics. Status tracks how much of each topic was covered." }, "meeting_type": { "type": "string", "description": "Descriptive meeting category in the meeting's language. Free text, not a fixed enum." } }, "required": [ "start_time" ], "additionalProperties": false, "description": "The record's fields.", "title": "Meeting" }, "private": { "type": "boolean", "description": "Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance." }, "external_ref": { "type": "object", "description": "Permanent, case-sensitive source identity within this workspace, resource type and private/workspace scope. It is independent of API key rotation and retry receipt expiry.", "properties": { "namespace": { "type": "string", "minLength": 1, "description": "A stable name for the source system, such as crm-production." }, "id": { "type": "string", "minLength": 1, "description": "The record ID in that source system." } }, "required": [ "namespace", "id" ], "additionalProperties": false } }, "required": [ "external_ref", "data" ], "additionalProperties": false, "examples": [ { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "title": "Northstar · project kickoff", "start_time": 1791277200000, "end_time": 1791279900000, "participants": [ { "name": "Jamie Lee", "email": "jamie@example.com" }, { "name": "Alex Morgan", "email": "alex@example.org", "ref": "e_person_alex" } ], "company_refs": [ "e_company_northstar" ] } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:Meeting record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "title": { "type": "string", "description": "Meeting title. May be absent when no title has been supplied." }, "started_by": { "type": "string", "description": "Host account ID. This is the member identity that owns the meeting; created_by is separate record provenance." }, "start_time": { "type": "number", "description": "Meeting start time in Unix milliseconds. Use a number, not an ISO date string, when filtering this field." }, "end_time": { "type": "number", "description": "Meeting end time in Unix milliseconds. May be absent before the meeting ends." }, "status": { "type": "string", "description": "Meeting lifecycle state, including live, paused and ended. This is an open string, not a closed enum; tolerate additional states." }, "language": { "type": "string", "description": "Language recorded for the meeting, such as en or no. It may differ from summary_language." }, "participants": { "type": "array", "items": { "title": "MeetingParticipant", "anyOf": [ { "type": "string", "title": "MeetingParticipant" }, { "type": "object", "properties": { "name": { "type": "string", "description": "Display name." }, "email": { "type": "string", "description": "Email address." }, "ref": { "type": "string", "description": "Person record ID for this attendee, when matched to a customer contact. It is not a workspace account ID." } }, "required": [], "additionalProperties": false, "title": "MeetingParticipant" } ] }, "description": "Attendee names or objects containing a name, email and optional Person record reference." }, "calendar_event_id": { "type": "string", "description": "ID of a `core:CalendarEvent` record. Find it with [meetings.ListCalendarEvents](/developers/reference/meetings/ListCalendarEvents) and use the top-level `id`. This is not an account ID or a display name." }, "sharing_external": { "type": "boolean", "description": "Whether external attendees were identified when the meeting was prepared. This is not permission to share the meeting externally; absence means this fact was not recorded." }, "call_direction": { "type": "string", "description": "Phone call direction, currently inbound or outbound. Absent for meetings without phone-call metadata." }, "call_outcome": { "type": "string", "description": "How a phone call ended, including completed, no_answer, busy, declined, canceled or failed. This is an open string." }, "call_duration_ms": { "type": "number", "description": "Recorded phone-call duration in milliseconds." }, "counterpart_e164": { "type": "string", "description": "Other party's phone number in international E.164 format, such as +4721001234." }, "call_forwarded": { "type": "boolean", "description": "Whether the incoming call was forwarded from another phone number." }, "conference_url": { "type": "string", "description": "Conference link from the calendar invitation, when one is available." }, "contact_refs": { "type": "array", "items": { "type": "string", "description": "id of a core:Person" }, "description": "Linked Person record IDs. Use has to filter for a particular contact." }, "company_refs": { "type": "array", "items": { "type": "string", "description": "id of a core:Company" }, "description": "Linked Company record IDs. Use has to filter for a particular company." }, "related_meetings": { "type": "array", "items": { "type": "string", "description": "id of a core:Meeting" }, "description": "IDs of related Meeting records. Each related record has its own access rules." }, "agenda": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." }, "subtopics": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." } }, "additionalProperties": false }, "description": "Second-level discussion topics; no deeper nesting is supported." } }, "additionalProperties": false }, "description": "Two-level agenda: topics and optional subtopics. Status tracks how much of each topic was covered." }, "meeting_type": { "type": "string", "description": "Descriptive meeting category in the meeting's language. Free text, not a fixed enum." }, "gist": { "type": "string", "description": "One- or two-line takeaway from the meeting." }, "summary_bullets": { "type": "array", "items": { "type": "string" }, "description": "Key points extracted from the meeting." }, "summary": { "type": "string", "description": "Full meeting summary formatted as Markdown." }, "summary_language": { "type": "string", "description": "Language of the generated summary, such as en or no." }, "custom_summary": { "type": "object", "properties": { "example": { "type": "string", "description": "Example output illustrating the desired summary style." }, "instructions": { "type": "string", "description": "Instructions to follow when generating the summary." } }, "additionalProperties": false, "description": "Instructions and optional example used to generate a custom summary. This is configuration, not the generated summary." } }, "required": [ "start_time", "status" ], "additionalProperties": false, "description": "The record's fields.", "title": "Meeting" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "MeetingRecord" }, "created": { "type": "boolean", "description": "True when this external reference created a record; false when it matched an existing record." } }, "required": [ "item", "created" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_meeting_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "title": "Northstar · project kickoff", "start_time": 1791277200000, "end_time": 1791279900000, "status": "ended", "started_by": "a_jamie", "participants": [ { "name": "Jamie Lee", "email": "jamie@example.com" }, { "name": "Alex Morgan", "email": "alex@example.org", "ref": "e_person_alex" } ], "company_refs": [ "e_company_northstar" ], "gist": "The team agreed to begin the pilot on 19 October.", "summary_bullets": [ "Alex will send the source data by Friday.", "Jamie will prepare the pilot workspace." ], "summary": "## Decisions\nStart the pilot on 19 October.\n\n## Next steps\n- Alex: send source data by Friday.\n- Jamie: prepare the workspace.", "summary_language": "en" } }, "created": true } ] } ``` --- # Generate meeting agenda Suggest an agenda for a meeting type. A meeting ID adds context from accessible attendees, invitations and previous summaries. Returns suggestions without saving them; uses workspace credits. POST https://api.brigg.app/v1/operations/meetings.GenerateMeetingAgenda ## Access & visibility Allow `meetings.GenerateMeetingAgenda` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `term` | string | Yes | The meeting type the person typed. At least 1 character. At most 120 characters. | | `meeting_id` | string | No | The core:Meeting entry id. At least 1 character. At most 128 characters. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `agenda` | array of string | Yes | Discussion topics planned for the meeting. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | ## Next steps [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.GenerateMeetingAgenda' \ -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 '{ "term": "Project 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.GenerateMeetingAgenda", { 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({ "term": "Project 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 = { "term": "Project kickoff" } request = Request( "https://api.brigg.app/v1/operations/meetings.GenerateMeetingAgenda", 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 { "agenda": [ "Objectives", "Responsibilities", "Next steps" ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "term": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The meeting type the person typed." }, "meeting_id": { "type": "string", "minLength": 1, "maxLength": 128, "description": "The core:Meeting entry id." } }, "required": [ "term" ], "additionalProperties": false, "examples": [ { "term": "Project kickoff" } ] } ``` ```json-schema-response { "type": "object", "properties": { "agenda": { "type": "array", "items": { "type": "string" }, "description": "Discussion topics planned for the meeting." } }, "required": [ "agenda" ], "additionalProperties": false, "examples": [ { "agenda": [ "Objectives", "Responsibilities", "Next steps" ] } ] } ``` --- # Get meeting finding Read a meeting finding by ID. Returns item: null when no visible record matches. POST https://api.brigg.app/v1/operations/meetings.GetMeetingFinding ## Access & visibility Allow `meetings.GetMeetingFinding` on your API key. Resource read permissions: `core:MeetingFinding`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:MeetingFinding` record. Use the relevant list operation to discover records. Use the record's top-level `id`, not a business field or account ID. | ## Response Returns **200 OK** with a JSON body. `item: null` means there is no matching record visible to this caller. It does not reveal whether an inaccessible record exists. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [MeetingFindingRecord](#meetingfindingrecord-response-item) or null | Yes | null when no such record | ### MeetingFindingRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:MeetingFinding record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [MeetingFinding](#meetingfinding-response-item-data) | Yes | The record's fields. | ### MeetingFinding · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `meeting_id` | string | Yes | ID of a `core:Meeting` record. Find it with [meetings.ListMeetings](/developers/reference/meetings/ListMeetings) and use the top-level `id`. This is not an account ID or a display name. | | `title` | string | Yes | Short heading for a finding from the meeting. | | `body` | string | Yes | Explanation or context for the finding. | | `source` | string | No | Source attribution supplied with this finding, when available. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [List meeting findings](/developers/reference/meetings/ListMeetingFindings) - [Create meeting finding](/developers/reference/meetings/CreateMeetingFinding) - [Upsert meeting finding](/developers/reference/meetings/UpsertMeetingFinding) - [Update meeting finding](/developers/reference/meetings/UpdateMeetingFinding) - [Delete meeting finding](/developers/reference/meetings/DeleteMeetingFinding) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.GetMeetingFinding' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "e_meetingfinding_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/meetings.GetMeetingFinding", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "id": "e_meetingfinding_example" }), }); 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 payload = { "id": "e_meetingfinding_example" } request = Request( "https://api.brigg.app/v1/operations/meetings.GetMeetingFinding", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "item": { "id": "e_meetingfinding_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "meeting_id": "e_meeting_kickoff", "title": "Pilot start agreed", "body": "The pilot starts on 19 October.", "source": "Meeting discussion" } } } ``` ### No visible record A missing or inaccessible record returns item: null. Do not treat this as proof that a record exists for another member. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.GetMeetingFinding' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "e_meetingfinding_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/meetings.GetMeetingFinding", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "id": "e_meetingfinding_example" }), }); 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 payload = { "id": "e_meetingfinding_example" } request = Request( "https://api.brigg.app/v1/operations/meetings.GetMeetingFinding", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "item": null } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:MeetingFinding` record. Use the relevant list operation to discover records. Use the record's top-level `id`, not a business field or account ID." } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_meetingfinding_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": [ "object", "null" ], "properties": { "id": { "type": "string", "description": "Stable core:MeetingFinding record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "meeting_id": { "type": "string", "description": "ID of a `core:Meeting` record. Find it with [meetings.ListMeetings](/developers/reference/meetings/ListMeetings) and use the top-level `id`. This is not an account ID or a display name." }, "title": { "type": "string", "description": "Short heading for a finding from the meeting." }, "body": { "type": "string", "description": "Explanation or context for the finding." }, "source": { "type": "string", "description": "Source attribution supplied with this finding, when available." } }, "required": [ "meeting_id", "title", "body" ], "additionalProperties": false, "description": "The record's fields.", "title": "MeetingFinding" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "null when no such record", "title": "MeetingFindingRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_meetingfinding_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "meeting_id": "e_meeting_kickoff", "title": "Pilot start agreed", "body": "The pilot starts on 19 October.", "source": "Meeting discussion" } } } ] } ``` --- # List meeting findings List meeting findings visible to the credential, with filtering, sorting and cursor pagination. POST https://api.brigg.app/v1/operations/meetings.ListMeetingFindings ## Access & visibility Allow `meetings.ListMeetingFindings` on your API key. Resource read permissions: `core:MeetingFinding`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `filters` | array of [object](#request-filters) | No | Conditions the row must ALL satisfy. | | `sort` | [object](#request-sort) | No | Sort order for the results. Defaults to updated_at descending, with id as a tie-breaker. | | `limit` | integer | No | Maximum number of results to return in this page. Continue with next_cursor when returned. Default: `100`. Minimum: 1. | | `cursor` | string | No | The `next_cursor` of the previous page. | ### request.filters[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | `data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private. Allowed: `"id"`, `"created_at"`, `"updated_at"`, `"created_by"`, `"private"`, `"data.meeting_id"`, `"data.title"`, `"data.body"`, `"data.source"`. | | `op` | string | Yes | Comparison operator. Use in with an array, or omit value for is_empty and is_not_empty. Allowed: `"eq"`, `"neq"`, `"contains"`, `"starts_with"`, `"gt"`, `"gte"`, `"lt"`, `"lte"`, `"in"`, `"has"`, `"is_empty"`, `"is_not_empty"`. | | `value` | JSON value | No | The comparison value; an array for `in`; omitted for is_empty / is_not_empty. | ### request.sort | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | `data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private. Allowed: `"id"`, `"created_at"`, `"updated_at"`, `"created_by"`, `"private"`, `"data.meeting_id"`, `"data.title"`, `"data.body"`, `"data.source"`. | | `direction` | string | No | Sort direction: asc for ascending or desc for descending. Allowed: `"asc"`, `"desc"`. | ## Filtering and sorting All conditions are combined with **AND**. Address business fields as `data.`, and record metadata as `id`, `created_at`, `updated_at`, `created_by` or `private`. A field path names one field; it does not traverse nested objects. | Operator | Meaning | Value | | --- | --- | --- | | `eq` | Equal to a scalar | String, number, boolean or null | | `neq` | Not equal; missing values also match | String, number, boolean or null | | `contains` | Case-insensitive text contains | String; % and _ are literal characters | | `starts_with` | Case-insensitive text prefix | String | | `gt`, `gte` | Greater than / at least | Number or string appropriate to the field | | `lt`, `lte` | Less than / at most | Number or string appropriate to the field | | `in` | Equal to any supplied scalar | Nonempty array of strings, numbers, booleans or null | | `has` | Array contains a string | One string; does not match properties inside array objects | | `is_empty` | Missing, null, empty string or empty array | Omit value | | `is_not_empty` | Has a nonempty value | Omit value | Match the stored field's type. Numeric business timestamps take Unix milliseconds; date-only business fields take `YYYY-MM-DD`. The record metadata fields `created_at` and `updated_at` also accept ISO timestamps for ordered comparisons. Sorting defaults to `updated_at` descending. If you supply `sort.field` without `sort.direction`, direction is `desc`. The record ID breaks ties; missing values sort last. ## Response Returns **200 OK** with a JSON body. An empty `items` array means this page contains no matching visible results. Follow `next_cursor` when present. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [MeetingFindingRecord](#meetingfindingrecord-response-items) | Yes | Records visible under the credential's grants and the selected data scope, matching the requested filters. Pass next_cursor as cursor to continue when a next cursor is returned. | | `next_cursor` | string | No | Pass this value as cursor to continue with the same filters, sort and credential. Omitted when there are no more results. | ### MeetingFindingRecord · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:MeetingFinding record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [MeetingFinding](#meetingfinding-response-items-data) | Yes | The record's fields. | ### MeetingFinding · response.items[].data | Field | Type | Required | Description | | --- | --- | --- | --- | | `meeting_id` | string | Yes | ID of a `core:Meeting` record. Find it with [meetings.ListMeetings](/developers/reference/meetings/ListMeetings) and use the top-level `id`. This is not an account ID or a display name. | | `title` | string | Yes | Short heading for a finding from the meeting. | | `body` | string | Yes | Explanation or context for the finding. | | `source` | string | No | Source attribution supplied with this finding, when available. | ## Pagination Pass `next_cursor` from the response as `cursor` on the next request. Keep the same filters, sort and acting identity. Stop when `next_cursor` is absent; do not infer completion from the number of items. The default page size is **100**; `limit` must be a positive integer. **Pagination is a live view, not a snapshot.** Changes between pages can move records across page boundaries. Upsert by record ID rather than appending blindly. For recurring synchronization, use an overlapping update window and deduplicate records. Periodically reconcile IDs to detect deletions. [Resource webhooks](/developers/webhooks) can supplement synchronization for eligible workspace-shared records only: they do not export private or project-scoped records. Personal data still needs polling and reconciliation. ```typescript const query = { "limit": 10 }; let cursor; do { const response = await fetch("https://api.brigg.app/v1/operations/meetings.ListMeetingFindings", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ ...query, ...(cursor ? { cursor } : {}) }), }); const page = await response.json(); if (!response.ok) throw new Error(`${response.status}: ${page.message}`); for (const item of page.items) { console.log(item); // Process or upsert each result. } cursor = page.next_cursor; } while (cursor); ``` ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | | 400 | `cursor_invalid` | Restart pagination with no cursor. | | 400 | `cursor_mismatch` | Use the cursor with the original filters, sort order and credential. | ## Next steps - [Get meeting finding](/developers/reference/meetings/GetMeetingFinding) - [Create meeting finding](/developers/reference/meetings/CreateMeetingFinding) - [Upsert meeting finding](/developers/reference/meetings/UpsertMeetingFinding) - [Update meeting finding](/developers/reference/meetings/UpdateMeetingFinding) - [Delete meeting finding](/developers/reference/meetings/DeleteMeetingFinding) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### First page Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.ListMeetingFindings' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "limit": 10 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/meetings.ListMeetingFindings", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "limit": 10 }), }); 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 payload = { "limit": 10 } request = Request( "https://api.brigg.app/v1/operations/meetings.ListMeetingFindings", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_meetingfinding_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "meeting_id": "e_meeting_kickoff", "title": "Pilot start agreed", "body": "The pilot starts on 19 October.", "source": "Meeting discussion" } } ] } ``` ### Findings from one meeting Use the same Meeting record ID as the meeting page. Findings and personal notes are different record types. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.ListMeetingFindings' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "limit": 50, "filters": [ { "field": "data.meeting_id", "op": "eq", "value": "e_meeting_kickoff" } ] }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/meetings.ListMeetingFindings", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "limit": 50, "filters": [ { "field": "data.meeting_id", "op": "eq", "value": "e_meeting_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 payload = { "limit": 50, "filters": [ { "field": "data.meeting_id", "op": "eq", "value": "e_meeting_kickoff" } ] } request = Request( "https://api.brigg.app/v1/operations/meetings.ListMeetingFindings", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_meetingfinding_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "meeting_id": "e_meeting_kickoff", "title": "Pilot start agreed", "body": "The pilot starts on 19 October.", "source": "Meeting discussion" } } ] } ``` ### Records updated since a checkpoint 6 October 2026 at 00:00 UTC. Use an overlap window and upsert by ID when synchronizing. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.ListMeetingFindings' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/meetings.ListMeetingFindings", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 }), }); 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 payload = { "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 } request = Request( "https://api.brigg.app/v1/operations/meetings.ListMeetingFindings", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_meetingfinding_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "meeting_id": "e_meeting_kickoff", "title": "Pilot start agreed", "body": "The pilot starts on 19 October.", "source": "Meeting discussion" } } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "filters": { "type": "array", "items": { "type": "object", "properties": { "field": { "type": "string", "description": "`data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private.", "enum": [ "id", "created_at", "updated_at", "created_by", "private", "data.meeting_id", "data.title", "data.body", "data.source" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "contains", "starts_with", "gt", "gte", "lt", "lte", "in", "has", "is_empty", "is_not_empty" ], "description": "Comparison operator. Use in with an array, or omit value for is_empty and is_not_empty." }, "value": { "description": "The comparison value; an array for `in`; omitted for is_empty / is_not_empty." } }, "required": [ "field", "op" ], "additionalProperties": false }, "description": "Conditions the row must ALL satisfy." }, "sort": { "type": "object", "properties": { "field": { "type": "string", "description": "`data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private.", "enum": [ "id", "created_at", "updated_at", "created_by", "private", "data.meeting_id", "data.title", "data.body", "data.source" ] }, "direction": { "type": "string", "enum": [ "asc", "desc" ], "description": "Sort direction: asc for ascending or desc for descending." } }, "required": [ "field" ], "additionalProperties": false, "description": "Sort order for the results. Defaults to updated_at descending, with id as a tie-breaker." }, "limit": { "type": "integer", "minimum": 1, "default": 100, "description": "Maximum number of results to return in this page. Continue with next_cursor when returned." }, "cursor": { "type": "string", "description": "The `next_cursor` of the previous page." } }, "additionalProperties": false, "examples": [ { "limit": 10 } ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:MeetingFinding record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "meeting_id": { "type": "string", "description": "ID of a `core:Meeting` record. Find it with [meetings.ListMeetings](/developers/reference/meetings/ListMeetings) and use the top-level `id`. This is not an account ID or a display name." }, "title": { "type": "string", "description": "Short heading for a finding from the meeting." }, "body": { "type": "string", "description": "Explanation or context for the finding." }, "source": { "type": "string", "description": "Source attribution supplied with this finding, when available." } }, "required": [ "meeting_id", "title", "body" ], "additionalProperties": false, "description": "The record's fields.", "title": "MeetingFinding" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "title": "MeetingFindingRecord" }, "description": "Records visible under the credential's grants and the selected data scope, matching the requested filters. Pass next_cursor as cursor to continue when a next cursor is returned." }, "next_cursor": { "type": "string", "description": "Pass this value as cursor to continue with the same filters, sort and credential. Omitted when there are no more results." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "id": "e_meetingfinding_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "meeting_id": "e_meeting_kickoff", "title": "Pilot start agreed", "body": "The pilot starts on 19 October.", "source": "Meeting discussion" } } ] } ] } ``` --- # Create meeting finding Create a meeting finding and return the saved record. POST https://api.brigg.app/v1/operations/meetings.CreateMeetingFinding ## Access & visibility Allow `meetings.CreateMeetingFinding` on your API key. Resource read permissions: `core:MeetingFinding`. Resource write permissions: `core:MeetingFinding`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `data` | [MeetingFinding](#meetingfinding-request-data) | Yes | The record's fields. | | `private` | boolean | No | Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance. | ### MeetingFinding · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `meeting_id` | string | Yes | ID of a `core:Meeting` record. Find it with [meetings.ListMeetings](/developers/reference/meetings/ListMeetings) and use the top-level `id`. This is not an account ID or a display name. | | `title` | string | Yes | Short heading for a finding from the meeting. | | `body` | string | Yes | Explanation or context for the finding. | | `source` | string | No | Source attribution supplied with this finding, when available. | ## Choose ownership deliberately Omitting `private`, or setting it to false, creates a workspace-shared record. Set `private: true` to create a record owned by the approved acting member. Private records require member delegation; a workspace-only credential cannot own a personal record. The credential’s exact resource grants authorize the write; private ownership and project membership remain enforced. A create is a new record, not an upsert. Reuse the same idempotency key only for retries of that logical creation. For recurring synchronization, use the resource’s upsert operation when available: it matches a permanent external reference. Otherwise keep the returned record ID and use the corresponding update operation for subsequent changes. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [MeetingFindingRecord](#meetingfindingrecord-response-item) | Yes | The requested record, including its metadata and data fields. | ### MeetingFindingRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:MeetingFinding record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [MeetingFinding](#meetingfinding-response-item-data) | Yes | The record's fields. | ### MeetingFinding · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `meeting_id` | string | Yes | ID of a `core:Meeting` record. Find it with [meetings.ListMeetings](/developers/reference/meetings/ListMeetings) and use the top-level `id`. This is not an account ID or a display name. | | `title` | string | Yes | Short heading for a finding from the meeting. | | `body` | string | Yes | Explanation or context for the finding. | | `source` | string | No | Source attribution supplied with this finding, when available. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List meeting findings](/developers/reference/meetings/ListMeetingFindings) - [Get meeting finding](/developers/reference/meetings/GetMeetingFinding) - [Upsert meeting finding](/developers/reference/meetings/UpsertMeetingFinding) - [Update meeting finding](/developers/reference/meetings/UpdateMeetingFinding) - [Delete meeting finding](/developers/reference/meetings/DeleteMeetingFinding) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.CreateMeetingFinding' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "data": { "meeting_id": "e_meeting_kickoff", "title": "Pilot start agreed", "body": "The pilot starts on 19 October.", "source": "Meeting discussion" } }' ``` #### TypeScript ```typescript 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.CreateMeetingFinding", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "data": { "meeting_id": "e_meeting_kickoff", "title": "Pilot start agreed", "body": "The pilot starts on 19 October.", "source": "Meeting discussion" } }), }); 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 = { "data": { "meeting_id": "e_meeting_kickoff", "title": "Pilot start agreed", "body": "The pilot starts on 19 October.", "source": "Meeting discussion" } } request = Request( "https://api.brigg.app/v1/operations/meetings.CreateMeetingFinding", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_meetingfinding_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "meeting_id": "e_meeting_kickoff", "title": "Pilot start agreed", "body": "The pilot starts on 19 October.", "source": "Meeting discussion" } } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "data": { "type": "object", "properties": { "meeting_id": { "type": "string", "description": "ID of a `core:Meeting` record. Find it with [meetings.ListMeetings](/developers/reference/meetings/ListMeetings) and use the top-level `id`. This is not an account ID or a display name." }, "title": { "type": "string", "description": "Short heading for a finding from the meeting." }, "body": { "type": "string", "description": "Explanation or context for the finding." }, "source": { "type": "string", "description": "Source attribution supplied with this finding, when available." } }, "required": [ "meeting_id", "title", "body" ], "additionalProperties": false, "description": "The record's fields.", "title": "MeetingFinding" }, "private": { "type": "boolean", "description": "Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance." } }, "required": [ "data" ], "additionalProperties": false, "examples": [ { "data": { "meeting_id": "e_meeting_kickoff", "title": "Pilot start agreed", "body": "The pilot starts on 19 October.", "source": "Meeting discussion" } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:MeetingFinding record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "meeting_id": { "type": "string", "description": "ID of a `core:Meeting` record. Find it with [meetings.ListMeetings](/developers/reference/meetings/ListMeetings) and use the top-level `id`. This is not an account ID or a display name." }, "title": { "type": "string", "description": "Short heading for a finding from the meeting." }, "body": { "type": "string", "description": "Explanation or context for the finding." }, "source": { "type": "string", "description": "Source attribution supplied with this finding, when available." } }, "required": [ "meeting_id", "title", "body" ], "additionalProperties": false, "description": "The record's fields.", "title": "MeetingFinding" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "MeetingFindingRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_meetingfinding_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "meeting_id": "e_meeting_kickoff", "title": "Pilot start agreed", "body": "The pilot starts on 19 October.", "source": "Meeting discussion" } } } ] } ``` --- # Delete meeting finding Delete a meeting finding by ID. Repeating a deletion returns already_deleted. POST https://api.brigg.app/v1/operations/meetings.DeleteMeetingFinding ## Access & visibility Allow `meetings.DeleteMeetingFinding` on your API key. Resource read permissions: `core:MeetingFinding`. Resource write permissions: `core:MeetingFinding`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:MeetingFinding` record. Use the relevant list operation to discover records. Use the record's top-level `id`, not a business field or account ID. | | `expected` | [object](#request-expected) | No | Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {"$absent":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource. | ### request.expected | Field | Type | Required | Description | | --- | --- | --- | --- | | `meeting_id` | string or [object](#request-expected-meeting-id) | No | Commit only if the previous meeting_id value matches; use $absent to require that this field is missing. | | `title` | string or [object](#request-expected-title) | No | Commit only if the previous title value matches; use $absent to require that this field is missing. | | `body` | string or [object](#request-expected-body) | No | Commit only if the previous body value matches; use $absent to require that this field is missing. | | `source` | string or [object](#request-expected-source) | No | Commit only if the previous source value matches; use $absent to require that this field is missing. | ### request.expected.meeting_id | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.title | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.body | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.source | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ## Deletion and retries A successful response reports whether this call removed the record or it was already absent. Check `cascaded` for dependent record IDs returned by the operation. Retrying the same action uses the original idempotency key. A successful deletion is not an archive you can restore through this operation. To avoid deleting a record someone has changed, read it first and put the relevant prior business values in `expected`. Keys are relative to `data`, not prefixed with `data.`. Use {"$absent": true} to require a missing field. A mismatch returns 409 conflict; read again and decide whether deletion is still appropriate. A revised action needs a new idempotency key. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `deleted` | string | Yes | deleted when this request removed the record; already_deleted when it was already absent. Allowed: `"deleted"`, `"already_deleted"`. | | `cascaded` | array of string | No | IDs of dependent records deleted with this 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `conflict` | A supplied expected value no longer matches. Read the record again before deciding whether to retry. | ## Next steps - [List meeting findings](/developers/reference/meetings/ListMeetingFindings) - [Get meeting finding](/developers/reference/meetings/GetMeetingFinding) - [Create meeting finding](/developers/reference/meetings/CreateMeetingFinding) - [Upsert meeting finding](/developers/reference/meetings/UpsertMeetingFinding) - [Update meeting finding](/developers/reference/meetings/UpdateMeetingFinding) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.DeleteMeetingFinding' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_meetingfinding_example" }' ``` #### TypeScript ```typescript 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.DeleteMeetingFinding", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_meetingfinding_example" }), }); 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_meetingfinding_example" } request = Request( "https://api.brigg.app/v1/operations/meetings.DeleteMeetingFinding", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "deleted": "deleted" } ``` ### Delete only if unchanged Use a value you actually read. A concurrent change refuses the write with 409 conflict. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.DeleteMeetingFinding' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_meetingfinding_example", "expected": { "meeting_id": "e_meeting_kickoff" } }' ``` #### TypeScript ```typescript 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.DeleteMeetingFinding", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_meetingfinding_example", "expected": { "meeting_id": "e_meeting_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_meetingfinding_example", "expected": { "meeting_id": "e_meeting_kickoff" } } request = Request( "https://api.brigg.app/v1/operations/meetings.DeleteMeetingFinding", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "deleted": "deleted" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:MeetingFinding` record. Use the relevant list operation to discover records. Use the record's top-level `id`, not a business field or account ID." }, "expected": { "type": "object", "description": "Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {\"$absent\":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource.", "additionalProperties": false, "properties": { "meeting_id": { "description": "Commit only if the previous meeting_id value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "ID of a `core:Meeting` record. Find it with [meetings.ListMeetings](/developers/reference/meetings/ListMeetings) and use the top-level `id`. This is not an account ID or a display name." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "title": { "description": "Commit only if the previous title value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Short heading for a finding from the meeting." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "body": { "description": "Commit only if the previous body value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Explanation or context for the finding." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "source": { "description": "Commit only if the previous source value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Source attribution supplied with this finding, when available." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] } } } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_meetingfinding_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "deleted": { "type": "string", "enum": [ "deleted", "already_deleted" ], "description": "deleted when this request removed the record; already_deleted when it was already absent." }, "cascaded": { "type": "array", "items": { "type": "string" }, "description": "IDs of dependent records deleted with this record." } }, "required": [ "deleted" ], "additionalProperties": false, "examples": [ { "deleted": "deleted" } ] } ``` --- # Update meeting finding Update a meeting finding by ID. Omitted fields stay unchanged; use unset to remove fields and expected to prevent overwriting a concurrent change. POST https://api.brigg.app/v1/operations/meetings.UpdateMeetingFinding ## Access & visibility Allow `meetings.UpdateMeetingFinding` on your API key. Resource read permissions: `core:MeetingFinding`. Resource write permissions: `core:MeetingFinding`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:MeetingFinding` record. Use the relevant list operation to discover records. Use the record's top-level `id`, not a business field or account ID. | | `data` | [MeetingFinding](#meetingfinding-request-data) | No | The fields to set. | | `unset` | array of string | No | Keys of `data` to remove. Each item: `"meeting_id"`, `"title"`, `"body"`, `"source"`. | | `expected` | [object](#request-expected) | No | Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {"$absent":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource. | ### MeetingFinding · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `meeting_id` | string | No | ID of a `core:Meeting` record. Find it with [meetings.ListMeetings](/developers/reference/meetings/ListMeetings) and use the top-level `id`. This is not an account ID or a display name. | | `title` | string | No | Short heading for a finding from the meeting. | | `body` | string | No | Explanation or context for the finding. | | `source` | string | No | Source attribution supplied with this finding, when available. | ### request.expected | Field | Type | Required | Description | | --- | --- | --- | --- | | `meeting_id` | string or [object](#request-expected-meeting-id) | No | Commit only if the previous meeting_id value matches; use $absent to require that this field is missing. | | `title` | string or [object](#request-expected-title) | No | Commit only if the previous title value matches; use $absent to require that this field is missing. | | `body` | string or [object](#request-expected-body) | No | Commit only if the previous body value matches; use $absent to require that this field is missing. | | `source` | string or [object](#request-expected-source) | No | Commit only if the previous source value matches; use $absent to require that this field is missing. | ### request.expected.meeting_id | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.title | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.body | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.source | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ## Update without losing changes Send only the business fields you want to change in `data`; omitted fields stay unchanged. Use `unset` to remove an optional field. Setting a field to null is a different action and is allowed only when its schema permits null. Use `expected` for a conditional update: supply the values you last read for the fields whose concurrent changes would matter. `{"$absent": true}` expects a missing field. A conflict means you must read the record again and decide how to reconcile the change. Keep the same idempotency key when retrying the original action; use a new key for a revised action. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [MeetingFindingRecord](#meetingfindingrecord-response-item) | Yes | The requested record, including its metadata and data fields. | ### MeetingFindingRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:MeetingFinding record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [MeetingFinding](#meetingfinding-response-item-data) | Yes | The record's fields. | ### MeetingFinding · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `meeting_id` | string | Yes | ID of a `core:Meeting` record. Find it with [meetings.ListMeetings](/developers/reference/meetings/ListMeetings) and use the top-level `id`. This is not an account ID or a display name. | | `title` | string | Yes | Short heading for a finding from the meeting. | | `body` | string | Yes | Explanation or context for the finding. | | `source` | string | No | Source attribution supplied with this finding, when available. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `conflict` | A supplied expected value no longer matches. Read the record again before deciding whether to retry. | ## Next steps - [List meeting findings](/developers/reference/meetings/ListMeetingFindings) - [Get meeting finding](/developers/reference/meetings/GetMeetingFinding) - [Create meeting finding](/developers/reference/meetings/CreateMeetingFinding) - [Upsert meeting finding](/developers/reference/meetings/UpsertMeetingFinding) - [Delete meeting finding](/developers/reference/meetings/DeleteMeetingFinding) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.UpdateMeetingFinding' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_meetingfinding_example", "data": { "body": "The pilot starts on 19 October; Alex supplies the source data." } }' ``` #### TypeScript ```typescript 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.UpdateMeetingFinding", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_meetingfinding_example", "data": { "body": "The pilot starts on 19 October; Alex supplies the source data." } }), }); 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_meetingfinding_example", "data": { "body": "The pilot starts on 19 October; Alex supplies the source data." } } request = Request( "https://api.brigg.app/v1/operations/meetings.UpdateMeetingFinding", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_meetingfinding_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "meeting_id": "e_meeting_kickoff", "title": "Pilot start agreed", "body": "The pilot starts on 19 October; Alex supplies the source data.", "source": "Meeting discussion" } } } ``` ### Update only if unchanged Use a value you actually read. A concurrent change refuses the write with 409 conflict. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.UpdateMeetingFinding' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_meetingfinding_example", "data": { "body": "The pilot starts on 19 October; Alex supplies the source data." }, "expected": { "meeting_id": "e_meeting_kickoff" } }' ``` #### TypeScript ```typescript 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.UpdateMeetingFinding", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_meetingfinding_example", "data": { "body": "The pilot starts on 19 October; Alex supplies the source data." }, "expected": { "meeting_id": "e_meeting_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_meetingfinding_example", "data": { "body": "The pilot starts on 19 October; Alex supplies the source data." }, "expected": { "meeting_id": "e_meeting_kickoff" } } request = Request( "https://api.brigg.app/v1/operations/meetings.UpdateMeetingFinding", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_meetingfinding_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "meeting_id": "e_meeting_kickoff", "title": "Pilot start agreed", "body": "The pilot starts on 19 October; Alex supplies the source data.", "source": "Meeting discussion" } } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:MeetingFinding` record. Use the relevant list operation to discover records. Use the record's top-level `id`, not a business field or account ID." }, "data": { "type": "object", "properties": { "meeting_id": { "type": "string", "description": "ID of a `core:Meeting` record. Find it with [meetings.ListMeetings](/developers/reference/meetings/ListMeetings) and use the top-level `id`. This is not an account ID or a display name." }, "title": { "type": "string", "description": "Short heading for a finding from the meeting." }, "body": { "type": "string", "description": "Explanation or context for the finding." }, "source": { "type": "string", "description": "Source attribution supplied with this finding, when available." } }, "required": [], "additionalProperties": false, "description": "The fields to set.", "title": "MeetingFinding" }, "unset": { "type": "array", "items": { "type": "string", "enum": [ "meeting_id", "title", "body", "source" ] }, "description": "Keys of `data` to remove." }, "expected": { "type": "object", "description": "Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {\"$absent\":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource.", "additionalProperties": false, "properties": { "meeting_id": { "description": "Commit only if the previous meeting_id value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "ID of a `core:Meeting` record. Find it with [meetings.ListMeetings](/developers/reference/meetings/ListMeetings) and use the top-level `id`. This is not an account ID or a display name." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "title": { "description": "Commit only if the previous title value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Short heading for a finding from the meeting." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "body": { "description": "Commit only if the previous body value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Explanation or context for the finding." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "source": { "description": "Commit only if the previous source value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Source attribution supplied with this finding, when available." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] } } } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_meetingfinding_example", "data": { "body": "The pilot starts on 19 October; Alex supplies the source data." } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:MeetingFinding record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "meeting_id": { "type": "string", "description": "ID of a `core:Meeting` record. Find it with [meetings.ListMeetings](/developers/reference/meetings/ListMeetings) and use the top-level `id`. This is not an account ID or a display name." }, "title": { "type": "string", "description": "Short heading for a finding from the meeting." }, "body": { "type": "string", "description": "Explanation or context for the finding." }, "source": { "type": "string", "description": "Source attribution supplied with this finding, when available." } }, "required": [ "meeting_id", "title", "body" ], "additionalProperties": false, "description": "The record's fields.", "title": "MeetingFinding" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "MeetingFindingRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_meetingfinding_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "meeting_id": "e_meeting_kickoff", "title": "Pilot start agreed", "body": "The pilot starts on 19 October; Alex supplies the source data.", "source": "Meeting discussion" } } } ] } ``` --- # Upsert meeting finding Create or update a meeting finding by a permanent external reference. Matching is exact within the workspace, resource type and ownership scope. Supplied fields replace their values; omitted fields stay unchanged. Deleted records are not recreated. POST https://api.brigg.app/v1/operations/meetings.UpsertMeetingFinding ## Access & visibility Allow `meetings.UpsertMeetingFinding` on your API key. Resource read permissions: `core:MeetingFinding`. Resource write permissions: `core:MeetingFinding`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `data` | [MeetingFinding](#meetingfinding-request-data) | Yes | The record's fields. | | `private` | boolean | No | Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance. | | `external_ref` | [object](#request-external-ref) | Yes | Permanent, case-sensitive source identity within this workspace, resource type and private/workspace scope. It is independent of API key rotation and retry receipt expiry. | ### MeetingFinding · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `meeting_id` | string | Yes | ID of a `core:Meeting` record. Find it with [meetings.ListMeetings](/developers/reference/meetings/ListMeetings) and use the top-level `id`. This is not an account ID or a display name. | | `title` | string | Yes | Short heading for a finding from the meeting. | | `body` | string | Yes | Explanation or context for the finding. | | `source` | string | No | Source attribution supplied with this finding, when available. | ### request.external_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `namespace` | string | Yes | A stable name for the source system, such as crm-production. At least 1 character. | | `id` | string | Yes | The record ID in that source system. At least 1 character. | ## Sync with a permanent external reference Choose a stable `external_ref.namespace` for your source system and put its record ID in `external_ref.id`. Matching is case-sensitive and scoped to this workspace, resource type and private/workspace ownership. The reference survives API key replacement and the 30-day retry receipt window. It does not match records by email or name. Send the required create fields each time. A missing reference creates a record; an existing reference updates only supplied fields and preserves everything else. `created` tells you which happened. Use the same idempotency key when retrying a lost response and a new key for a later source change. Concurrent calls cannot create duplicate records. A deleted or inaccessible match is refused; the operation does not restore it or make a replacement. Use the returned `item.id` with the regular update operation when you need `unset` or a conditional `expected` edit. Changing `private` chooses a different ownership scope; it does not transfer an existing record. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [MeetingFindingRecord](#meetingfindingrecord-response-item) | Yes | The requested record, including its metadata and data fields. | | `created` | boolean | Yes | True when this external reference created a record; false when it matched an existing record. | ### MeetingFindingRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:MeetingFinding record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [MeetingFinding](#meetingfinding-response-item-data) | Yes | The record's fields. | ### MeetingFinding · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `meeting_id` | string | Yes | ID of a `core:Meeting` record. Find it with [meetings.ListMeetings](/developers/reference/meetings/ListMeetings) and use the top-level `id`. This is not an account ID or a display name. | | `title` | string | Yes | Short heading for a finding from the meeting. | | `body` | string | Yes | Explanation or context for the finding. | | `source` | string | No | Source attribution supplied with this finding, when available. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List meeting findings](/developers/reference/meetings/ListMeetingFindings) - [Get meeting finding](/developers/reference/meetings/GetMeetingFinding) - [Create meeting finding](/developers/reference/meetings/CreateMeetingFinding) - [Update meeting finding](/developers/reference/meetings/UpdateMeetingFinding) - [Delete meeting finding](/developers/reference/meetings/DeleteMeetingFinding) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### First sync Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.UpsertMeetingFinding' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "meeting_id": "e_meeting_kickoff", "title": "Pilot start agreed", "body": "The pilot starts on 19 October.", "source": "Meeting discussion" } }' ``` #### TypeScript ```typescript 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.UpsertMeetingFinding", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "meeting_id": "e_meeting_kickoff", "title": "Pilot start agreed", "body": "The pilot starts on 19 October.", "source": "Meeting discussion" } }), }); 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 = { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "meeting_id": "e_meeting_kickoff", "title": "Pilot start agreed", "body": "The pilot starts on 19 October.", "source": "Meeting discussion" } } request = Request( "https://api.brigg.app/v1/operations/meetings.UpsertMeetingFinding", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_meetingfinding_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "meeting_id": "e_meeting_kickoff", "title": "Pilot start agreed", "body": "The pilot starts on 19 October.", "source": "Meeting discussion" } }, "created": true } ``` ### Later sync The same external reference returns the same record ID. Use a new idempotency key for a later source change. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.UpsertMeetingFinding' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "meeting_id": "e_meeting_kickoff", "title": "Pilot start agreed", "body": "The pilot starts on 19 October.", "source": "Meeting discussion" } }' ``` #### TypeScript ```typescript 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.UpsertMeetingFinding", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "meeting_id": "e_meeting_kickoff", "title": "Pilot start agreed", "body": "The pilot starts on 19 October.", "source": "Meeting discussion" } }), }); 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 = { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "meeting_id": "e_meeting_kickoff", "title": "Pilot start agreed", "body": "The pilot starts on 19 October.", "source": "Meeting discussion" } } request = Request( "https://api.brigg.app/v1/operations/meetings.UpsertMeetingFinding", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_meetingfinding_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "meeting_id": "e_meeting_kickoff", "title": "Pilot start agreed", "body": "The pilot starts on 19 October.", "source": "Meeting discussion" } }, "created": false } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "data": { "type": "object", "properties": { "meeting_id": { "type": "string", "description": "ID of a `core:Meeting` record. Find it with [meetings.ListMeetings](/developers/reference/meetings/ListMeetings) and use the top-level `id`. This is not an account ID or a display name." }, "title": { "type": "string", "description": "Short heading for a finding from the meeting." }, "body": { "type": "string", "description": "Explanation or context for the finding." }, "source": { "type": "string", "description": "Source attribution supplied with this finding, when available." } }, "required": [ "meeting_id", "title", "body" ], "additionalProperties": false, "description": "The record's fields.", "title": "MeetingFinding" }, "private": { "type": "boolean", "description": "Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance." }, "external_ref": { "type": "object", "description": "Permanent, case-sensitive source identity within this workspace, resource type and private/workspace scope. It is independent of API key rotation and retry receipt expiry.", "properties": { "namespace": { "type": "string", "minLength": 1, "description": "A stable name for the source system, such as crm-production." }, "id": { "type": "string", "minLength": 1, "description": "The record ID in that source system." } }, "required": [ "namespace", "id" ], "additionalProperties": false } }, "required": [ "external_ref", "data" ], "additionalProperties": false, "examples": [ { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "meeting_id": "e_meeting_kickoff", "title": "Pilot start agreed", "body": "The pilot starts on 19 October.", "source": "Meeting discussion" } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:MeetingFinding record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "meeting_id": { "type": "string", "description": "ID of a `core:Meeting` record. Find it with [meetings.ListMeetings](/developers/reference/meetings/ListMeetings) and use the top-level `id`. This is not an account ID or a display name." }, "title": { "type": "string", "description": "Short heading for a finding from the meeting." }, "body": { "type": "string", "description": "Explanation or context for the finding." }, "source": { "type": "string", "description": "Source attribution supplied with this finding, when available." } }, "required": [ "meeting_id", "title", "body" ], "additionalProperties": false, "description": "The record's fields.", "title": "MeetingFinding" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "MeetingFindingRecord" }, "created": { "type": "boolean", "description": "True when this external reference created a record; false when it matched an existing record." } }, "required": [ "item", "created" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_meetingfinding_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "meeting_id": "e_meeting_kickoff", "title": "Pilot start agreed", "body": "The pilot starts on 19 October.", "source": "Meeting discussion" } }, "created": true } ] } ``` --- # Get meeting note Read a meeting note by ID. Returns item: null when no visible record matches. POST https://api.brigg.app/v1/operations/meetings.GetMeetingNote ## Access & visibility Allow `meetings.GetMeetingNote` on your API key. Resource read permissions: `core:MeetingNote`. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:MeetingNote` record. Use the relevant list operation to discover records. Use the record's top-level `id`, not a business field or account ID. | ## Response Returns **200 OK** with a JSON body. `item: null` means there is no matching record visible to this caller. It does not reveal whether an inaccessible record exists. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. Sharing a meeting does not share personal notes. An API key needs approved delegation to a member whose access permits these notes. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [MeetingNoteRecord](#meetingnoterecord-response-item) or null | Yes | null when no such record | ### MeetingNoteRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:MeetingNote record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [MeetingNote](#meetingnote-response-item-data) | Yes | The record's fields. | ### MeetingNote · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `meeting_id` | string | Yes | ID of a `core:Meeting` record. Find it with [meetings.ListMeetings](/developers/reference/meetings/ListMeetings) and use the top-level `id`. This is not an account ID or a display name. | | `text` | string | No | The acting member's personal notes for the meeting. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 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. | ## Next steps - [List meeting notes](/developers/reference/meetings/ListMeetingNotes) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.GetMeetingNote' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Brigg-Act-As: $BRIGG_ACT_AS" \ --data-raw '{ "id": "e_meetingnote_example" }' ``` #### 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 response = await fetch("https://api.brigg.app/v1/operations/meetings.GetMeetingNote", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Brigg-Act-As": actAs, }, body: JSON.stringify({ "id": "e_meetingnote_example" }), }); 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 payload = { "id": "e_meetingnote_example" } request = Request( "https://api.brigg.app/v1/operations/meetings.GetMeetingNote", 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"], }, 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 { "item": { "id": "e_meetingnote_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": true, "data": { "meeting_id": "e_meeting_kickoff", "text": "Ask Alex about the onboarding checklist." } } } ``` ### No visible record A missing or inaccessible record returns item: null. Do not treat this as proof that a record exists for another member. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.GetMeetingNote' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Brigg-Act-As: $BRIGG_ACT_AS" \ --data-raw '{ "id": "e_meetingnote_example" }' ``` #### 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 response = await fetch("https://api.brigg.app/v1/operations/meetings.GetMeetingNote", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Brigg-Act-As": actAs, }, body: JSON.stringify({ "id": "e_meetingnote_example" }), }); 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 payload = { "id": "e_meetingnote_example" } request = Request( "https://api.brigg.app/v1/operations/meetings.GetMeetingNote", 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"], }, 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 { "item": null } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:MeetingNote` record. Use the relevant list operation to discover records. Use the record's top-level `id`, not a business field or account ID." } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_meetingnote_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": [ "object", "null" ], "properties": { "id": { "type": "string", "description": "Stable core:MeetingNote record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "meeting_id": { "type": "string", "description": "ID of a `core:Meeting` record. Find it with [meetings.ListMeetings](/developers/reference/meetings/ListMeetings) and use the top-level `id`. This is not an account ID or a display name." }, "text": { "type": "string", "description": "The acting member's personal notes for the meeting." } }, "required": [ "meeting_id" ], "additionalProperties": false, "description": "The record's fields.", "title": "MeetingNote" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "null when no such record", "title": "MeetingNoteRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_meetingnote_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": true, "data": { "meeting_id": "e_meeting_kickoff", "text": "Ask Alex about the onboarding checklist." } } } ] } ``` --- # List meeting notes List meeting notes visible to the credential, with filtering, sorting and cursor pagination. POST https://api.brigg.app/v1/operations/meetings.ListMeetingNotes ## Access & visibility Allow `meetings.ListMeetingNotes` on your API key. Resource read permissions: `core:MeetingNote`. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `filters` | array of [object](#request-filters) | No | Conditions the row must ALL satisfy. | | `sort` | [object](#request-sort) | No | Sort order for the results. Defaults to updated_at descending, with id as a tie-breaker. | | `limit` | integer | No | Maximum number of results to return in this page. Continue with next_cursor when returned. Default: `100`. Minimum: 1. | | `cursor` | string | No | The `next_cursor` of the previous page. | ### request.filters[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | `data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private. Allowed: `"id"`, `"created_at"`, `"updated_at"`, `"created_by"`, `"private"`, `"data.meeting_id"`, `"data.text"`. | | `op` | string | Yes | Comparison operator. Use in with an array, or omit value for is_empty and is_not_empty. Allowed: `"eq"`, `"neq"`, `"contains"`, `"starts_with"`, `"gt"`, `"gte"`, `"lt"`, `"lte"`, `"in"`, `"has"`, `"is_empty"`, `"is_not_empty"`. | | `value` | JSON value | No | The comparison value; an array for `in`; omitted for is_empty / is_not_empty. | ### request.sort | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | `data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private. Allowed: `"id"`, `"created_at"`, `"updated_at"`, `"created_by"`, `"private"`, `"data.meeting_id"`, `"data.text"`. | | `direction` | string | No | Sort direction: asc for ascending or desc for descending. Allowed: `"asc"`, `"desc"`. | ## Filtering and sorting All conditions are combined with **AND**. Address business fields as `data.`, and record metadata as `id`, `created_at`, `updated_at`, `created_by` or `private`. A field path names one field; it does not traverse nested objects. | Operator | Meaning | Value | | --- | --- | --- | | `eq` | Equal to a scalar | String, number, boolean or null | | `neq` | Not equal; missing values also match | String, number, boolean or null | | `contains` | Case-insensitive text contains | String; % and _ are literal characters | | `starts_with` | Case-insensitive text prefix | String | | `gt`, `gte` | Greater than / at least | Number or string appropriate to the field | | `lt`, `lte` | Less than / at most | Number or string appropriate to the field | | `in` | Equal to any supplied scalar | Nonempty array of strings, numbers, booleans or null | | `has` | Array contains a string | One string; does not match properties inside array objects | | `is_empty` | Missing, null, empty string or empty array | Omit value | | `is_not_empty` | Has a nonempty value | Omit value | Match the stored field's type. Numeric business timestamps take Unix milliseconds; date-only business fields take `YYYY-MM-DD`. The record metadata fields `created_at` and `updated_at` also accept ISO timestamps for ordered comparisons. Sorting defaults to `updated_at` descending. If you supply `sort.field` without `sort.direction`, direction is `desc`. The record ID breaks ties; missing values sort last. ## Response Returns **200 OK** with a JSON body. An empty `items` array means this page contains no matching visible results. Follow `next_cursor` when present. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. Sharing a meeting does not share personal notes. An API key needs approved delegation to a member whose access permits these notes. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [MeetingNoteRecord](#meetingnoterecord-response-items) | Yes | Records visible under the credential's grants and the selected data scope, matching the requested filters. Pass next_cursor as cursor to continue when a next cursor is returned. | | `next_cursor` | string | No | Pass this value as cursor to continue with the same filters, sort and credential. Omitted when there are no more results. | ### MeetingNoteRecord · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:MeetingNote record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [MeetingNote](#meetingnote-response-items-data) | Yes | The record's fields. | ### MeetingNote · response.items[].data | Field | Type | Required | Description | | --- | --- | --- | --- | | `meeting_id` | string | Yes | ID of a `core:Meeting` record. Find it with [meetings.ListMeetings](/developers/reference/meetings/ListMeetings) and use the top-level `id`. This is not an account ID or a display name. | | `text` | string | No | The acting member's personal notes for the meeting. | ## Pagination Pass `next_cursor` from the response as `cursor` on the next request. Keep the same filters, sort and acting identity. Stop when `next_cursor` is absent; do not infer completion from the number of items. The default page size is **100**; `limit` must be a positive integer. **Pagination is a live view, not a snapshot.** Changes between pages can move records across page boundaries. Upsert by record ID rather than appending blindly. For recurring synchronization, use an overlapping update window and deduplicate records. Periodically reconcile IDs to detect deletions. [Resource webhooks](/developers/webhooks) can supplement synchronization for eligible workspace-shared records only: they do not export private or project-scoped records. Personal data still needs polling and reconciliation. ```typescript const actAs = process.env.BRIGG_ACT_AS; if (!actAs) throw new Error("Set BRIGG_ACT_AS to an approved member account ID."); const query = { "limit": 10 }; let cursor; do { const response = await fetch("https://api.brigg.app/v1/operations/meetings.ListMeetingNotes", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Brigg-Act-As": actAs, }, body: JSON.stringify({ ...query, ...(cursor ? { cursor } : {}) }), }); const page = await response.json(); if (!response.ok) throw new Error(`${response.status}: ${page.message}`); for (const item of page.items) { console.log(item); // Process or upsert each result. } cursor = page.next_cursor; } while (cursor); ``` ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 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. | | 400 | `cursor_invalid` | Restart pagination with no cursor. | | 400 | `cursor_mismatch` | Use the cursor with the original filters, sort order and credential. | ## Next steps - [Get meeting note](/developers/reference/meetings/GetMeetingNote) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### First page Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.ListMeetingNotes' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Brigg-Act-As: $BRIGG_ACT_AS" \ --data-raw '{ "limit": 10 }' ``` #### 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 response = await fetch("https://api.brigg.app/v1/operations/meetings.ListMeetingNotes", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Brigg-Act-As": actAs, }, body: JSON.stringify({ "limit": 10 }), }); 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 payload = { "limit": 10 } request = Request( "https://api.brigg.app/v1/operations/meetings.ListMeetingNotes", 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"], }, 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 { "items": [ { "id": "e_meetingnote_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": true, "data": { "meeting_id": "e_meeting_kickoff", "text": "Ask Alex about the onboarding checklist." } } ] } ``` ### My notes for one meeting Use a Meeting record ID. Approved member delegation determines whose personal notes can be read; sharing the meeting does not share notes. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.ListMeetingNotes' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Brigg-Act-As: $BRIGG_ACT_AS" \ --data-raw '{ "limit": 50, "filters": [ { "field": "data.meeting_id", "op": "eq", "value": "e_meeting_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 response = await fetch("https://api.brigg.app/v1/operations/meetings.ListMeetingNotes", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Brigg-Act-As": actAs, }, body: JSON.stringify({ "limit": 50, "filters": [ { "field": "data.meeting_id", "op": "eq", "value": "e_meeting_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 payload = { "limit": 50, "filters": [ { "field": "data.meeting_id", "op": "eq", "value": "e_meeting_kickoff" } ] } request = Request( "https://api.brigg.app/v1/operations/meetings.ListMeetingNotes", 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"], }, 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 { "items": [ { "id": "e_meetingnote_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": true, "data": { "meeting_id": "e_meeting_kickoff", "text": "Ask Alex about the onboarding checklist." } } ] } ``` ### Records updated since a checkpoint 6 October 2026 at 00:00 UTC. Use an overlap window and upsert by ID when synchronizing. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.ListMeetingNotes' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Brigg-Act-As: $BRIGG_ACT_AS" \ --data-raw '{ "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 }' ``` #### 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 response = await fetch("https://api.brigg.app/v1/operations/meetings.ListMeetingNotes", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Brigg-Act-As": actAs, }, body: JSON.stringify({ "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 }), }); 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 payload = { "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 } request = Request( "https://api.brigg.app/v1/operations/meetings.ListMeetingNotes", 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"], }, 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 { "items": [ { "id": "e_meetingnote_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": true, "data": { "meeting_id": "e_meeting_kickoff", "text": "Ask Alex about the onboarding checklist." } } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "filters": { "type": "array", "items": { "type": "object", "properties": { "field": { "type": "string", "description": "`data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private.", "enum": [ "id", "created_at", "updated_at", "created_by", "private", "data.meeting_id", "data.text" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "contains", "starts_with", "gt", "gte", "lt", "lte", "in", "has", "is_empty", "is_not_empty" ], "description": "Comparison operator. Use in with an array, or omit value for is_empty and is_not_empty." }, "value": { "description": "The comparison value; an array for `in`; omitted for is_empty / is_not_empty." } }, "required": [ "field", "op" ], "additionalProperties": false }, "description": "Conditions the row must ALL satisfy." }, "sort": { "type": "object", "properties": { "field": { "type": "string", "description": "`data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private.", "enum": [ "id", "created_at", "updated_at", "created_by", "private", "data.meeting_id", "data.text" ] }, "direction": { "type": "string", "enum": [ "asc", "desc" ], "description": "Sort direction: asc for ascending or desc for descending." } }, "required": [ "field" ], "additionalProperties": false, "description": "Sort order for the results. Defaults to updated_at descending, with id as a tie-breaker." }, "limit": { "type": "integer", "minimum": 1, "default": 100, "description": "Maximum number of results to return in this page. Continue with next_cursor when returned." }, "cursor": { "type": "string", "description": "The `next_cursor` of the previous page." } }, "additionalProperties": false, "examples": [ { "limit": 10 } ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:MeetingNote record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "meeting_id": { "type": "string", "description": "ID of a `core:Meeting` record. Find it with [meetings.ListMeetings](/developers/reference/meetings/ListMeetings) and use the top-level `id`. This is not an account ID or a display name." }, "text": { "type": "string", "description": "The acting member's personal notes for the meeting." } }, "required": [ "meeting_id" ], "additionalProperties": false, "description": "The record's fields.", "title": "MeetingNote" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "title": "MeetingNoteRecord" }, "description": "Records visible under the credential's grants and the selected data scope, matching the requested filters. Pass next_cursor as cursor to continue when a next cursor is returned." }, "next_cursor": { "type": "string", "description": "Pass this value as cursor to continue with the same filters, sort and credential. Omitted when there are no more results." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "id": "e_meetingnote_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": true, "data": { "meeting_id": "e_meeting_kickoff", "text": "Ask Alex about the onboarding checklist." } } ] } ] } ``` --- # Save meeting note Save the caller's private notes for a meeting. Colleagues cannot read these notes even when the meeting is shared. POST https://api.brigg.app/v1/operations/meetings.SaveMeetingNote ## Access & visibility Allow `meetings.SaveMeetingNote` on your API key. Resource write permissions: `core:MeetingNote`. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | Use the Meeting record's top-level id, not a calendar event ID. [meetings.ListMeetings](/developers/reference/meetings/ListMeetings). At least 1 character. At most 128 characters. | | `text` | string | Yes | The caller's private notes for the meeting, whole — this REPLACES the existing note, it does not append. At most 20000 characters. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | ## Next steps - [List meetings](/developers/reference/meetings/ListMeetings) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.SaveMeetingNote' \ -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_example", "text": "Confirm the onboarding checklist with Alex." }' ``` #### 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.SaveMeetingNote", { 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_example", "text": "Confirm the onboarding checklist with Alex." }), }); 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_example", "text": "Confirm the onboarding checklist with Alex." } request = Request( "https://api.brigg.app/v1/operations/meetings.SaveMeetingNote", 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 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Use the Meeting record's top-level id, not a calendar event ID. [meetings.ListMeetings](/developers/reference/meetings/ListMeetings)." }, "text": { "type": "string", "maxLength": 20000, "description": "The caller's private notes for the meeting, whole — this REPLACES the existing note, it does not append." } }, "required": [ "id", "text" ], "additionalProperties": false, "examples": [ { "id": "e_example", "text": "Confirm the onboarding checklist with Alex." } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." } }, "required": [ "ok" ], "additionalProperties": false, "examples": [ { "ok": true } ] } ``` --- # Get meeting template Read a meeting template by ID. Returns item: null when no visible record matches. POST https://api.brigg.app/v1/operations/meetings.GetMeetingTemplate ## Access & visibility Allow `meetings.GetMeetingTemplate` on your API key. Resource read permissions: `core:MeetingTemplate`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:MeetingTemplate` record. Find it with [meetings.ListMeetingTemplates](/developers/reference/meetings/ListMeetingTemplates). Use the record's top-level `id`, not a business field or account ID. | ## Response Returns **200 OK** with a JSON body. `item: null` means there is no matching record visible to this caller. It does not reveal whether an inaccessible record exists. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [MeetingTemplateRecord](#meetingtemplaterecord-response-item) or null | Yes | null when no such record | ### MeetingTemplateRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:MeetingTemplate record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [MeetingTemplate](#meetingtemplate-response-item-data) | Yes | The record's fields. | ### MeetingTemplate · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Name used to select this meeting template. | | `agenda` | array of [object](#response-item-data-agenda) | No | Default two-level agenda to use when applying this template. | | `custom_summary` | [object](#response-item-data-custom-summary) | No | Instructions and optional example for generating summaries from meetings using this template. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | | `sort_order` | number | No | Relative ordering value used to display templates. | ### response.item.data.agenda[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | | `subtopics` | array of [object](#response-item-data-agenda-subtopics) | No | Second-level discussion topics; no deeper nesting is supported. | ### response.item.data.agenda[].subtopics[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | ### response.item.data.custom_summary | Field | Type | Required | Description | | --- | --- | --- | --- | | `example` | string | No | Example output illustrating the desired summary style. | | `instructions` | string | No | Instructions to follow when generating the summary. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [List meeting templates](/developers/reference/meetings/ListMeetingTemplates) - [Create meeting template](/developers/reference/meetings/CreateMeetingTemplate) - [Upsert meeting template](/developers/reference/meetings/UpsertMeetingTemplate) - [Update meeting template](/developers/reference/meetings/UpdateMeetingTemplate) - [Delete meeting template](/developers/reference/meetings/DeleteMeetingTemplate) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.GetMeetingTemplate' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "e_meetingtemplate_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/meetings.GetMeetingTemplate", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "id": "e_meetingtemplate_example" }), }); 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 payload = { "id": "e_meetingtemplate_example" } request = Request( "https://api.brigg.app/v1/operations/meetings.GetMeetingTemplate", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "item": { "id": "e_meetingtemplate_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "Project kickoff", "agenda": [ { "id": "objectives", "name": "Objectives", "status": "None" }, { "id": "next-steps", "name": "Next steps", "status": "None" } ], "custom_summary": { "instructions": "Summarize decisions, action owners and due dates." } } } } ``` ### No visible record A missing or inaccessible record returns item: null. Do not treat this as proof that a record exists for another member. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.GetMeetingTemplate' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "e_meetingtemplate_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/meetings.GetMeetingTemplate", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "id": "e_meetingtemplate_example" }), }); 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 payload = { "id": "e_meetingtemplate_example" } request = Request( "https://api.brigg.app/v1/operations/meetings.GetMeetingTemplate", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "item": null } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:MeetingTemplate` record. Find it with [meetings.ListMeetingTemplates](/developers/reference/meetings/ListMeetingTemplates). Use the record's top-level `id`, not a business field or account ID." } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_meetingtemplate_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": [ "object", "null" ], "properties": { "id": { "type": "string", "description": "Stable core:MeetingTemplate record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "name": { "type": "string", "description": "Name used to select this meeting template." }, "agenda": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." }, "subtopics": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." } }, "additionalProperties": false }, "description": "Second-level discussion topics; no deeper nesting is supported." } }, "additionalProperties": false }, "description": "Default two-level agenda to use when applying this template." }, "custom_summary": { "type": "object", "properties": { "example": { "type": "string", "description": "Example output illustrating the desired summary style." }, "instructions": { "type": "string", "description": "Instructions to follow when generating the summary." } }, "additionalProperties": false, "description": "Instructions and optional example for generating summaries from meetings using this template." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, "sort_order": { "type": "number", "description": "Relative ordering value used to display templates." } }, "required": [ "name" ], "additionalProperties": false, "description": "The record's fields.", "title": "MeetingTemplate" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "null when no such record", "title": "MeetingTemplateRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_meetingtemplate_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "Project kickoff", "agenda": [ { "id": "objectives", "name": "Objectives", "status": "None" }, { "id": "next-steps", "name": "Next steps", "status": "None" } ], "custom_summary": { "instructions": "Summarize decisions, action owners and due dates." } } } } ] } ``` --- # List meeting templates List meeting templates visible to the credential, with filtering, sorting and cursor pagination. POST https://api.brigg.app/v1/operations/meetings.ListMeetingTemplates ## Access & visibility Allow `meetings.ListMeetingTemplates` on your API key. Resource read permissions: `core:MeetingTemplate`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `filters` | array of [object](#request-filters) | No | Conditions the row must ALL satisfy. | | `sort` | [object](#request-sort) | No | Sort order for the results. Defaults to updated_at descending, with id as a tie-breaker. | | `limit` | integer | No | Maximum number of results to return in this page. Continue with next_cursor when returned. Default: `100`. Minimum: 1. | | `cursor` | string | No | The `next_cursor` of the previous page. | ### request.filters[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | `data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private. Allowed: `"id"`, `"created_at"`, `"updated_at"`, `"created_by"`, `"private"`, `"data.name"`, `"data.agenda"`, `"data.custom_summary"`, `"data.tags"`, `"data.sort_order"`. | | `op` | string | Yes | Comparison operator. Use in with an array, or omit value for is_empty and is_not_empty. Allowed: `"eq"`, `"neq"`, `"contains"`, `"starts_with"`, `"gt"`, `"gte"`, `"lt"`, `"lte"`, `"in"`, `"has"`, `"is_empty"`, `"is_not_empty"`. | | `value` | JSON value | No | The comparison value; an array for `in`; omitted for is_empty / is_not_empty. | ### request.sort | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | `data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private. Allowed: `"id"`, `"created_at"`, `"updated_at"`, `"created_by"`, `"private"`, `"data.name"`, `"data.agenda"`, `"data.custom_summary"`, `"data.tags"`, `"data.sort_order"`. | | `direction` | string | No | Sort direction: asc for ascending or desc for descending. Allowed: `"asc"`, `"desc"`. | ## Filtering and sorting All conditions are combined with **AND**. Address business fields as `data.`, and record metadata as `id`, `created_at`, `updated_at`, `created_by` or `private`. A field path names one field; it does not traverse nested objects. | Operator | Meaning | Value | | --- | --- | --- | | `eq` | Equal to a scalar | String, number, boolean or null | | `neq` | Not equal; missing values also match | String, number, boolean or null | | `contains` | Case-insensitive text contains | String; % and _ are literal characters | | `starts_with` | Case-insensitive text prefix | String | | `gt`, `gte` | Greater than / at least | Number or string appropriate to the field | | `lt`, `lte` | Less than / at most | Number or string appropriate to the field | | `in` | Equal to any supplied scalar | Nonempty array of strings, numbers, booleans or null | | `has` | Array contains a string | One string; does not match properties inside array objects | | `is_empty` | Missing, null, empty string or empty array | Omit value | | `is_not_empty` | Has a nonempty value | Omit value | Match the stored field's type. Numeric business timestamps take Unix milliseconds; date-only business fields take `YYYY-MM-DD`. The record metadata fields `created_at` and `updated_at` also accept ISO timestamps for ordered comparisons. Sorting defaults to `updated_at` descending. If you supply `sort.field` without `sort.direction`, direction is `desc`. The record ID breaks ties; missing values sort last. ## Response Returns **200 OK** with a JSON body. An empty `items` array means this page contains no matching visible results. Follow `next_cursor` when present. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [MeetingTemplateRecord](#meetingtemplaterecord-response-items) | Yes | Records visible under the credential's grants and the selected data scope, matching the requested filters. Pass next_cursor as cursor to continue when a next cursor is returned. | | `next_cursor` | string | No | Pass this value as cursor to continue with the same filters, sort and credential. Omitted when there are no more results. | ### MeetingTemplateRecord · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:MeetingTemplate record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [MeetingTemplate](#meetingtemplate-response-items-data) | Yes | The record's fields. | ### MeetingTemplate · response.items[].data | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Name used to select this meeting template. | | `agenda` | array of [object](#response-items-data-agenda) | No | Default two-level agenda to use when applying this template. | | `custom_summary` | [object](#response-items-data-custom-summary) | No | Instructions and optional example for generating summaries from meetings using this template. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | | `sort_order` | number | No | Relative ordering value used to display templates. | ### response.items[].data.agenda[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | | `subtopics` | array of [object](#response-items-data-agenda-subtopics) | No | Second-level discussion topics; no deeper nesting is supported. | ### response.items[].data.agenda[].subtopics[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | ### response.items[].data.custom_summary | Field | Type | Required | Description | | --- | --- | --- | --- | | `example` | string | No | Example output illustrating the desired summary style. | | `instructions` | string | No | Instructions to follow when generating the summary. | ## Pagination Pass `next_cursor` from the response as `cursor` on the next request. Keep the same filters, sort and acting identity. Stop when `next_cursor` is absent; do not infer completion from the number of items. The default page size is **100**; `limit` must be a positive integer. **Pagination is a live view, not a snapshot.** Changes between pages can move records across page boundaries. Upsert by record ID rather than appending blindly. For recurring synchronization, use an overlapping update window and deduplicate records. Periodically reconcile IDs to detect deletions. [Resource webhooks](/developers/webhooks) can supplement synchronization for eligible workspace-shared records only: they do not export private or project-scoped records. Personal data still needs polling and reconciliation. ```typescript const query = { "limit": 10 }; let cursor; do { const response = await fetch("https://api.brigg.app/v1/operations/meetings.ListMeetingTemplates", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ ...query, ...(cursor ? { cursor } : {}) }), }); const page = await response.json(); if (!response.ok) throw new Error(`${response.status}: ${page.message}`); for (const item of page.items) { console.log(item); // Process or upsert each result. } cursor = page.next_cursor; } while (cursor); ``` ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | | 400 | `cursor_invalid` | Restart pagination with no cursor. | | 400 | `cursor_mismatch` | Use the cursor with the original filters, sort order and credential. | ## Next steps - [Get meeting template](/developers/reference/meetings/GetMeetingTemplate) - [Create meeting template](/developers/reference/meetings/CreateMeetingTemplate) - [Upsert meeting template](/developers/reference/meetings/UpsertMeetingTemplate) - [Update meeting template](/developers/reference/meetings/UpdateMeetingTemplate) - [Delete meeting template](/developers/reference/meetings/DeleteMeetingTemplate) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### First page Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.ListMeetingTemplates' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "limit": 10 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/meetings.ListMeetingTemplates", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "limit": 10 }), }); 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 payload = { "limit": 10 } request = Request( "https://api.brigg.app/v1/operations/meetings.ListMeetingTemplates", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_meetingtemplate_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "Project kickoff", "agenda": [ { "id": "objectives", "name": "Objectives", "status": "None" }, { "id": "next-steps", "name": "Next steps", "status": "None" } ], "custom_summary": { "instructions": "Summarize decisions, action owners and due dates." } } } ] } ``` ### Find a meeting template Search its display name. This is a meeting agenda/summary template, not a Word document template. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.ListMeetingTemplates' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "limit": 50, "filters": [ { "field": "data.name", "op": "contains", "value": "kickoff" } ] }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/meetings.ListMeetingTemplates", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "limit": 50, "filters": [ { "field": "data.name", "op": "contains", "value": "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 payload = { "limit": 50, "filters": [ { "field": "data.name", "op": "contains", "value": "kickoff" } ] } request = Request( "https://api.brigg.app/v1/operations/meetings.ListMeetingTemplates", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_meetingtemplate_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "kickoff", "agenda": [ { "id": "objectives", "name": "Objectives", "status": "None" }, { "id": "next-steps", "name": "Next steps", "status": "None" } ], "custom_summary": { "instructions": "Summarize decisions, action owners and due dates." } } } ] } ``` ### Records updated since a checkpoint 6 October 2026 at 00:00 UTC. Use an overlap window and upsert by ID when synchronizing. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.ListMeetingTemplates' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/meetings.ListMeetingTemplates", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 }), }); 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 payload = { "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 } request = Request( "https://api.brigg.app/v1/operations/meetings.ListMeetingTemplates", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_meetingtemplate_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "Project kickoff", "agenda": [ { "id": "objectives", "name": "Objectives", "status": "None" }, { "id": "next-steps", "name": "Next steps", "status": "None" } ], "custom_summary": { "instructions": "Summarize decisions, action owners and due dates." } } } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "filters": { "type": "array", "items": { "type": "object", "properties": { "field": { "type": "string", "description": "`data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private.", "enum": [ "id", "created_at", "updated_at", "created_by", "private", "data.name", "data.agenda", "data.custom_summary", "data.tags", "data.sort_order" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "contains", "starts_with", "gt", "gte", "lt", "lte", "in", "has", "is_empty", "is_not_empty" ], "description": "Comparison operator. Use in with an array, or omit value for is_empty and is_not_empty." }, "value": { "description": "The comparison value; an array for `in`; omitted for is_empty / is_not_empty." } }, "required": [ "field", "op" ], "additionalProperties": false }, "description": "Conditions the row must ALL satisfy." }, "sort": { "type": "object", "properties": { "field": { "type": "string", "description": "`data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private.", "enum": [ "id", "created_at", "updated_at", "created_by", "private", "data.name", "data.agenda", "data.custom_summary", "data.tags", "data.sort_order" ] }, "direction": { "type": "string", "enum": [ "asc", "desc" ], "description": "Sort direction: asc for ascending or desc for descending." } }, "required": [ "field" ], "additionalProperties": false, "description": "Sort order for the results. Defaults to updated_at descending, with id as a tie-breaker." }, "limit": { "type": "integer", "minimum": 1, "default": 100, "description": "Maximum number of results to return in this page. Continue with next_cursor when returned." }, "cursor": { "type": "string", "description": "The `next_cursor` of the previous page." } }, "additionalProperties": false, "examples": [ { "limit": 10 } ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:MeetingTemplate record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "name": { "type": "string", "description": "Name used to select this meeting template." }, "agenda": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." }, "subtopics": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." } }, "additionalProperties": false }, "description": "Second-level discussion topics; no deeper nesting is supported." } }, "additionalProperties": false }, "description": "Default two-level agenda to use when applying this template." }, "custom_summary": { "type": "object", "properties": { "example": { "type": "string", "description": "Example output illustrating the desired summary style." }, "instructions": { "type": "string", "description": "Instructions to follow when generating the summary." } }, "additionalProperties": false, "description": "Instructions and optional example for generating summaries from meetings using this template." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, "sort_order": { "type": "number", "description": "Relative ordering value used to display templates." } }, "required": [ "name" ], "additionalProperties": false, "description": "The record's fields.", "title": "MeetingTemplate" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "title": "MeetingTemplateRecord" }, "description": "Records visible under the credential's grants and the selected data scope, matching the requested filters. Pass next_cursor as cursor to continue when a next cursor is returned." }, "next_cursor": { "type": "string", "description": "Pass this value as cursor to continue with the same filters, sort and credential. Omitted when there are no more results." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "id": "e_meetingtemplate_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "Project kickoff", "agenda": [ { "id": "objectives", "name": "Objectives", "status": "None" }, { "id": "next-steps", "name": "Next steps", "status": "None" } ], "custom_summary": { "instructions": "Summarize decisions, action owners and due dates." } } } ] } ] } ``` --- # Create meeting template Create a meeting template and return the saved record. POST https://api.brigg.app/v1/operations/meetings.CreateMeetingTemplate ## Access & visibility Allow `meetings.CreateMeetingTemplate` on your API key. Resource read permissions: `core:MeetingTemplate`. Resource write permissions: `core:MeetingTemplate`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `data` | [MeetingTemplate](#meetingtemplate-request-data) | Yes | The record's fields. | | `private` | boolean | No | Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance. | ### MeetingTemplate · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Name used to select this meeting template. | | `agenda` | array of [object](#request-data-agenda) | No | Default two-level agenda to use when applying this template. | | `custom_summary` | [object](#request-data-custom-summary) | No | Instructions and optional example for generating summaries from meetings using this template. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | | `sort_order` | number | No | Relative ordering value used to display templates. | ### request.data.agenda[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | | `subtopics` | array of [object](#request-data-agenda-subtopics) | No | Second-level discussion topics; no deeper nesting is supported. | ### request.data.agenda[].subtopics[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | ### request.data.custom_summary | Field | Type | Required | Description | | --- | --- | --- | --- | | `example` | string | No | Example output illustrating the desired summary style. | | `instructions` | string | No | Instructions to follow when generating the summary. | ## Choose ownership deliberately Omitting `private`, or setting it to false, creates a workspace-shared record. Set `private: true` to create a record owned by the approved acting member. Private records require member delegation; a workspace-only credential cannot own a personal record. The credential’s exact resource grants authorize the write; private ownership and project membership remain enforced. A create is a new record, not an upsert. Reuse the same idempotency key only for retries of that logical creation. For recurring synchronization, use the resource’s upsert operation when available: it matches a permanent external reference. Otherwise keep the returned record ID and use the corresponding update operation for subsequent changes. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [MeetingTemplateRecord](#meetingtemplaterecord-response-item) | Yes | The requested record, including its metadata and data fields. | ### MeetingTemplateRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:MeetingTemplate record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [MeetingTemplate](#meetingtemplate-response-item-data) | Yes | The record's fields. | ### MeetingTemplate · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Name used to select this meeting template. | | `agenda` | array of [object](#response-item-data-agenda) | No | Default two-level agenda to use when applying this template. | | `custom_summary` | [object](#response-item-data-custom-summary) | No | Instructions and optional example for generating summaries from meetings using this template. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | | `sort_order` | number | No | Relative ordering value used to display templates. | ### response.item.data.agenda[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | | `subtopics` | array of [object](#response-item-data-agenda-subtopics) | No | Second-level discussion topics; no deeper nesting is supported. | ### response.item.data.agenda[].subtopics[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | ### response.item.data.custom_summary | Field | Type | Required | Description | | --- | --- | --- | --- | | `example` | string | No | Example output illustrating the desired summary style. | | `instructions` | string | No | Instructions to follow when generating the summary. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List meeting templates](/developers/reference/meetings/ListMeetingTemplates) - [Get meeting template](/developers/reference/meetings/GetMeetingTemplate) - [Upsert meeting template](/developers/reference/meetings/UpsertMeetingTemplate) - [Update meeting template](/developers/reference/meetings/UpdateMeetingTemplate) - [Delete meeting template](/developers/reference/meetings/DeleteMeetingTemplate) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.CreateMeetingTemplate' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "data": { "name": "Project kickoff", "agenda": [ { "id": "objectives", "name": "Objectives", "status": "None" }, { "id": "next-steps", "name": "Next steps", "status": "None" } ], "custom_summary": { "instructions": "Summarize decisions, action owners and due dates." } } }' ``` #### TypeScript ```typescript 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.CreateMeetingTemplate", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "data": { "name": "Project kickoff", "agenda": [ { "id": "objectives", "name": "Objectives", "status": "None" }, { "id": "next-steps", "name": "Next steps", "status": "None" } ], "custom_summary": { "instructions": "Summarize decisions, action owners and due dates." } } }), }); 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 = { "data": { "name": "Project kickoff", "agenda": [ { "id": "objectives", "name": "Objectives", "status": "None" }, { "id": "next-steps", "name": "Next steps", "status": "None" } ], "custom_summary": { "instructions": "Summarize decisions, action owners and due dates." } } } request = Request( "https://api.brigg.app/v1/operations/meetings.CreateMeetingTemplate", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_meetingtemplate_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "Project kickoff", "agenda": [ { "id": "objectives", "name": "Objectives", "status": "None" }, { "id": "next-steps", "name": "Next steps", "status": "None" } ], "custom_summary": { "instructions": "Summarize decisions, action owners and due dates." } } } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "data": { "type": "object", "properties": { "name": { "type": "string", "description": "Name used to select this meeting template." }, "agenda": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." }, "subtopics": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." } }, "additionalProperties": false }, "description": "Second-level discussion topics; no deeper nesting is supported." } }, "additionalProperties": false }, "description": "Default two-level agenda to use when applying this template." }, "custom_summary": { "type": "object", "properties": { "example": { "type": "string", "description": "Example output illustrating the desired summary style." }, "instructions": { "type": "string", "description": "Instructions to follow when generating the summary." } }, "additionalProperties": false, "description": "Instructions and optional example for generating summaries from meetings using this template." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, "sort_order": { "type": "number", "description": "Relative ordering value used to display templates." } }, "required": [ "name" ], "additionalProperties": false, "description": "The record's fields.", "title": "MeetingTemplate" }, "private": { "type": "boolean", "description": "Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance." } }, "required": [ "data" ], "additionalProperties": false, "examples": [ { "data": { "name": "Project kickoff", "agenda": [ { "id": "objectives", "name": "Objectives", "status": "None" }, { "id": "next-steps", "name": "Next steps", "status": "None" } ], "custom_summary": { "instructions": "Summarize decisions, action owners and due dates." } } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:MeetingTemplate record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "name": { "type": "string", "description": "Name used to select this meeting template." }, "agenda": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." }, "subtopics": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." } }, "additionalProperties": false }, "description": "Second-level discussion topics; no deeper nesting is supported." } }, "additionalProperties": false }, "description": "Default two-level agenda to use when applying this template." }, "custom_summary": { "type": "object", "properties": { "example": { "type": "string", "description": "Example output illustrating the desired summary style." }, "instructions": { "type": "string", "description": "Instructions to follow when generating the summary." } }, "additionalProperties": false, "description": "Instructions and optional example for generating summaries from meetings using this template." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, "sort_order": { "type": "number", "description": "Relative ordering value used to display templates." } }, "required": [ "name" ], "additionalProperties": false, "description": "The record's fields.", "title": "MeetingTemplate" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "MeetingTemplateRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_meetingtemplate_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "Project kickoff", "agenda": [ { "id": "objectives", "name": "Objectives", "status": "None" }, { "id": "next-steps", "name": "Next steps", "status": "None" } ], "custom_summary": { "instructions": "Summarize decisions, action owners and due dates." } } } } ] } ``` --- # Delete meeting template Delete a meeting template by ID. Repeating a deletion returns already_deleted. POST https://api.brigg.app/v1/operations/meetings.DeleteMeetingTemplate ## Access & visibility Allow `meetings.DeleteMeetingTemplate` on your API key. Resource read permissions: `core:MeetingTemplate`. Resource write permissions: `core:MeetingTemplate`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:MeetingTemplate` record. Find it with [meetings.ListMeetingTemplates](/developers/reference/meetings/ListMeetingTemplates). Use the record's top-level `id`, not a business field or account ID. | | `expected` | [object](#request-expected) | No | Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {"$absent":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource. | ### request.expected | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string or [object](#request-expected-name) | No | Commit only if the previous name value matches; use $absent to require that this field is missing. | | `agenda` | array of [object](#request-expected-agenda) or [object](#request-expected-agenda) | No | Commit only if the previous agenda value matches; use $absent to require that this field is missing. | | `custom_summary` | [object (2 variants)](#request-expected-custom-summary) | No | Commit only if the previous custom_summary value matches; use $absent to require that this field is missing. | | `tags` | array of string or [object](#request-expected-tags) | No | Commit only if the previous tags value matches; use $absent to require that this field is missing. | | `sort_order` | number or [object](#request-expected-sort-order) | No | Commit only if the previous sort_order value matches; use $absent to require that this field is missing. | ### request.expected.name | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.agenda | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.agenda[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | | `subtopics` | array of [object](#request-expected-agenda-subtopics) | No | Second-level discussion topics; no deeper nesting is supported. | ### request.expected.agenda[].subtopics[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | ### request.expected.custom_summary #### Variant 1 | Field | Type | Required | Description | | --- | --- | --- | --- | | `example` | string | No | Example output illustrating the desired summary style. | | `instructions` | string | No | Instructions to follow when generating the summary. | #### $absent = true | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.tags | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.sort_order | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ## Deletion and retries A successful response reports whether this call removed the record or it was already absent. Check `cascaded` for dependent record IDs returned by the operation. Retrying the same action uses the original idempotency key. A successful deletion is not an archive you can restore through this operation. To avoid deleting a record someone has changed, read it first and put the relevant prior business values in `expected`. Keys are relative to `data`, not prefixed with `data.`. Use {"$absent": true} to require a missing field. A mismatch returns 409 conflict; read again and decide whether deletion is still appropriate. A revised action needs a new idempotency key. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `deleted` | string | Yes | deleted when this request removed the record; already_deleted when it was already absent. Allowed: `"deleted"`, `"already_deleted"`. | | `cascaded` | array of string | No | IDs of dependent records deleted with this 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `conflict` | A supplied expected value no longer matches. Read the record again before deciding whether to retry. | ## Next steps - [List meeting templates](/developers/reference/meetings/ListMeetingTemplates) - [Get meeting template](/developers/reference/meetings/GetMeetingTemplate) - [Create meeting template](/developers/reference/meetings/CreateMeetingTemplate) - [Upsert meeting template](/developers/reference/meetings/UpsertMeetingTemplate) - [Update meeting template](/developers/reference/meetings/UpdateMeetingTemplate) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.DeleteMeetingTemplate' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_meetingtemplate_example" }' ``` #### TypeScript ```typescript 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.DeleteMeetingTemplate", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_meetingtemplate_example" }), }); 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_meetingtemplate_example" } request = Request( "https://api.brigg.app/v1/operations/meetings.DeleteMeetingTemplate", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "deleted": "deleted" } ``` ### Delete only if unchanged Use a value you actually read. A concurrent change refuses the write with 409 conflict. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.DeleteMeetingTemplate' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_meetingtemplate_example", "expected": { "name": "Project kickoff" } }' ``` #### TypeScript ```typescript 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.DeleteMeetingTemplate", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_meetingtemplate_example", "expected": { "name": "Project 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_meetingtemplate_example", "expected": { "name": "Project kickoff" } } request = Request( "https://api.brigg.app/v1/operations/meetings.DeleteMeetingTemplate", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "deleted": "deleted" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:MeetingTemplate` record. Find it with [meetings.ListMeetingTemplates](/developers/reference/meetings/ListMeetingTemplates). Use the record's top-level `id`, not a business field or account ID." }, "expected": { "type": "object", "description": "Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {\"$absent\":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource.", "additionalProperties": false, "properties": { "name": { "description": "Commit only if the previous name value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Name used to select this meeting template." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "agenda": { "description": "Commit only if the previous agenda value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." }, "subtopics": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." } }, "additionalProperties": false }, "description": "Second-level discussion topics; no deeper nesting is supported." } }, "additionalProperties": false }, "description": "Default two-level agenda to use when applying this template." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "custom_summary": { "description": "Commit only if the previous custom_summary value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "object", "properties": { "example": { "type": "string", "description": "Example output illustrating the desired summary style." }, "instructions": { "type": "string", "description": "Instructions to follow when generating the summary." } }, "additionalProperties": false, "description": "Instructions and optional example for generating summaries from meetings using this template." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "tags": { "description": "Commit only if the previous tags value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "sort_order": { "description": "Commit only if the previous sort_order value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "number", "description": "Relative ordering value used to display templates." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] } } } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_meetingtemplate_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "deleted": { "type": "string", "enum": [ "deleted", "already_deleted" ], "description": "deleted when this request removed the record; already_deleted when it was already absent." }, "cascaded": { "type": "array", "items": { "type": "string" }, "description": "IDs of dependent records deleted with this record." } }, "required": [ "deleted" ], "additionalProperties": false, "examples": [ { "deleted": "deleted" } ] } ``` --- # Set meeting template sharing Share a meeting template with the workspace or return it to its owner's private templates without changing its content. POST https://api.brigg.app/v1/operations/meetings.SetMeetingTemplateSharing ## Access & visibility Allow `meetings.SetMeetingTemplateSharing` on your API key. Resource write permissions: `core:MeetingTemplate`. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | Top-level id from [List meeting templates](/developers/reference/meetings/ListMeetingTemplates). Use the template record identity, not a Meeting ID or a generated document template_id. At least 1 character. At most 128 characters. | | `shared` | boolean | Yes | True shares the template with the workspace; false returns it to its owner's private templates. | ## Share reading access while keeping responsibility Sharing makes the template readable across the workspace. It does not give every reader authority to edit, delete or unshare it. For an already shared template, the member recorded as its responsible creator or a workspace owner/administrator can change sharing. Private templates must be visible to the acting member. When unshared, the template returns to its recorded creator if that person remains an active member. Otherwise the acting member becomes its private owner. Existing content stays intact; future reads by other members can no longer find it. The response confirms the requested shared state, not the owner's account ID. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | | `shared` | boolean | Yes | Whether the meeting or template is shared with the workspace. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | | 400 | `not_a_meeting_template` | Use the id of a MeetingTemplate from ListMeetingTemplates, not a Meeting or document template. | ## Next steps - [List meeting templates](/developers/reference/meetings/ListMeetingTemplates) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Share with the workspace Select a template visible to the acting member. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.SetMeetingTemplateSharing' \ -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_template_project_review", "shared": true }' ``` #### 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.SetMeetingTemplateSharing", { 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_template_project_review", "shared": true }), }); 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_template_project_review", "shared": True } request = Request( "https://api.brigg.app/v1/operations/meetings.SetMeetingTemplateSharing", 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, "shared": true } ``` ### Return to personal templates Confirm the acting member's authority and the ownership behavior before removing workspace access. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.SetMeetingTemplateSharing' \ -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_template_project_review", "shared": false }' ``` #### 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.SetMeetingTemplateSharing", { 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_template_project_review", "shared": false }), }); 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_template_project_review", "shared": False } request = Request( "https://api.brigg.app/v1/operations/meetings.SetMeetingTemplateSharing", 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, "shared": false } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Top-level id from [List meeting templates](/developers/reference/meetings/ListMeetingTemplates). Use the template record identity, not a Meeting ID or a generated document template_id." }, "shared": { "type": "boolean", "description": "True shares the template with the workspace; false returns it to its owner's private templates." } }, "required": [ "id", "shared" ], "additionalProperties": false, "examples": [ { "id": "e_template_project_review", "shared": true } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." }, "shared": { "type": "boolean", "description": "Whether the meeting or template is shared with the workspace." } }, "required": [ "ok", "shared" ], "additionalProperties": false, "examples": [ { "ok": true, "shared": true } ] } ``` --- # Update meeting template Update a meeting template by ID. Omitted fields stay unchanged; use unset to remove fields and expected to prevent overwriting a concurrent change. POST https://api.brigg.app/v1/operations/meetings.UpdateMeetingTemplate ## Access & visibility Allow `meetings.UpdateMeetingTemplate` on your API key. Resource read permissions: `core:MeetingTemplate`. Resource write permissions: `core:MeetingTemplate`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:MeetingTemplate` record. Find it with [meetings.ListMeetingTemplates](/developers/reference/meetings/ListMeetingTemplates). Use the record's top-level `id`, not a business field or account ID. | | `data` | [MeetingTemplate](#meetingtemplate-request-data) | No | The fields to set. | | `unset` | array of string | No | Keys of `data` to remove. Each item: `"name"`, `"agenda"`, `"custom_summary"`, `"tags"`, `"sort_order"`. | | `expected` | [object](#request-expected) | No | Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {"$absent":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource. | ### MeetingTemplate · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | No | Name used to select this meeting template. | | `agenda` | array of [object](#request-data-agenda) | No | Default two-level agenda to use when applying this template. | | `custom_summary` | [object](#request-data-custom-summary) | No | Instructions and optional example for generating summaries from meetings using this template. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | | `sort_order` | number | No | Relative ordering value used to display templates. | ### request.data.agenda[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | | `subtopics` | array of [object](#request-data-agenda-subtopics) | No | Second-level discussion topics; no deeper nesting is supported. | ### request.data.agenda[].subtopics[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | ### request.data.custom_summary | Field | Type | Required | Description | | --- | --- | --- | --- | | `example` | string | No | Example output illustrating the desired summary style. | | `instructions` | string | No | Instructions to follow when generating the summary. | ### request.expected | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string or [object](#request-expected-name) | No | Commit only if the previous name value matches; use $absent to require that this field is missing. | | `agenda` | array of [object](#request-expected-agenda) or [object](#request-expected-agenda) | No | Commit only if the previous agenda value matches; use $absent to require that this field is missing. | | `custom_summary` | [object (2 variants)](#request-expected-custom-summary) | No | Commit only if the previous custom_summary value matches; use $absent to require that this field is missing. | | `tags` | array of string or [object](#request-expected-tags) | No | Commit only if the previous tags value matches; use $absent to require that this field is missing. | | `sort_order` | number or [object](#request-expected-sort-order) | No | Commit only if the previous sort_order value matches; use $absent to require that this field is missing. | ### request.expected.name | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.agenda | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.agenda[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | | `subtopics` | array of [object](#request-expected-agenda-subtopics) | No | Second-level discussion topics; no deeper nesting is supported. | ### request.expected.agenda[].subtopics[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | ### request.expected.custom_summary #### Variant 1 | Field | Type | Required | Description | | --- | --- | --- | --- | | `example` | string | No | Example output illustrating the desired summary style. | | `instructions` | string | No | Instructions to follow when generating the summary. | #### $absent = true | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.tags | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.sort_order | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ## Update without losing changes Send only the business fields you want to change in `data`; omitted fields stay unchanged. Use `unset` to remove an optional field. Setting a field to null is a different action and is allowed only when its schema permits null. Use `expected` for a conditional update: supply the values you last read for the fields whose concurrent changes would matter. `{"$absent": true}` expects a missing field. A conflict means you must read the record again and decide how to reconcile the change. Keep the same idempotency key when retrying the original action; use a new key for a revised action. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [MeetingTemplateRecord](#meetingtemplaterecord-response-item) | Yes | The requested record, including its metadata and data fields. | ### MeetingTemplateRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:MeetingTemplate record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [MeetingTemplate](#meetingtemplate-response-item-data) | Yes | The record's fields. | ### MeetingTemplate · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Name used to select this meeting template. | | `agenda` | array of [object](#response-item-data-agenda) | No | Default two-level agenda to use when applying this template. | | `custom_summary` | [object](#response-item-data-custom-summary) | No | Instructions and optional example for generating summaries from meetings using this template. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | | `sort_order` | number | No | Relative ordering value used to display templates. | ### response.item.data.agenda[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | | `subtopics` | array of [object](#response-item-data-agenda-subtopics) | No | Second-level discussion topics; no deeper nesting is supported. | ### response.item.data.agenda[].subtopics[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | ### response.item.data.custom_summary | Field | Type | Required | Description | | --- | --- | --- | --- | | `example` | string | No | Example output illustrating the desired summary style. | | `instructions` | string | No | Instructions to follow when generating the summary. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `conflict` | A supplied expected value no longer matches. Read the record again before deciding whether to retry. | ## Next steps - [List meeting templates](/developers/reference/meetings/ListMeetingTemplates) - [Get meeting template](/developers/reference/meetings/GetMeetingTemplate) - [Create meeting template](/developers/reference/meetings/CreateMeetingTemplate) - [Upsert meeting template](/developers/reference/meetings/UpsertMeetingTemplate) - [Delete meeting template](/developers/reference/meetings/DeleteMeetingTemplate) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.UpdateMeetingTemplate' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_meetingtemplate_example", "data": { "name": "Customer project kickoff" } }' ``` #### TypeScript ```typescript 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.UpdateMeetingTemplate", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_meetingtemplate_example", "data": { "name": "Customer project 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_meetingtemplate_example", "data": { "name": "Customer project kickoff" } } request = Request( "https://api.brigg.app/v1/operations/meetings.UpdateMeetingTemplate", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_meetingtemplate_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "Customer project kickoff", "agenda": [ { "id": "objectives", "name": "Objectives", "status": "None" }, { "id": "next-steps", "name": "Next steps", "status": "None" } ], "custom_summary": { "instructions": "Summarize decisions, action owners and due dates." } } } } ``` ### Update only if unchanged Use a value you actually read. A concurrent change refuses the write with 409 conflict. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.UpdateMeetingTemplate' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_meetingtemplate_example", "data": { "name": "Customer project kickoff" }, "expected": { "name": "Project kickoff" } }' ``` #### TypeScript ```typescript 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.UpdateMeetingTemplate", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_meetingtemplate_example", "data": { "name": "Customer project kickoff" }, "expected": { "name": "Project 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_meetingtemplate_example", "data": { "name": "Customer project kickoff" }, "expected": { "name": "Project kickoff" } } request = Request( "https://api.brigg.app/v1/operations/meetings.UpdateMeetingTemplate", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_meetingtemplate_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "Customer project kickoff", "agenda": [ { "id": "objectives", "name": "Objectives", "status": "None" }, { "id": "next-steps", "name": "Next steps", "status": "None" } ], "custom_summary": { "instructions": "Summarize decisions, action owners and due dates." } } } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:MeetingTemplate` record. Find it with [meetings.ListMeetingTemplates](/developers/reference/meetings/ListMeetingTemplates). Use the record's top-level `id`, not a business field or account ID." }, "data": { "type": "object", "properties": { "name": { "type": "string", "description": "Name used to select this meeting template." }, "agenda": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." }, "subtopics": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." } }, "additionalProperties": false }, "description": "Second-level discussion topics; no deeper nesting is supported." } }, "additionalProperties": false }, "description": "Default two-level agenda to use when applying this template." }, "custom_summary": { "type": "object", "properties": { "example": { "type": "string", "description": "Example output illustrating the desired summary style." }, "instructions": { "type": "string", "description": "Instructions to follow when generating the summary." } }, "additionalProperties": false, "description": "Instructions and optional example for generating summaries from meetings using this template." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, "sort_order": { "type": "number", "description": "Relative ordering value used to display templates." } }, "required": [], "additionalProperties": false, "description": "The fields to set.", "title": "MeetingTemplate" }, "unset": { "type": "array", "items": { "type": "string", "enum": [ "name", "agenda", "custom_summary", "tags", "sort_order" ] }, "description": "Keys of `data` to remove." }, "expected": { "type": "object", "description": "Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {\"$absent\":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource.", "additionalProperties": false, "properties": { "name": { "description": "Commit only if the previous name value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Name used to select this meeting template." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "agenda": { "description": "Commit only if the previous agenda value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." }, "subtopics": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." } }, "additionalProperties": false }, "description": "Second-level discussion topics; no deeper nesting is supported." } }, "additionalProperties": false }, "description": "Default two-level agenda to use when applying this template." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "custom_summary": { "description": "Commit only if the previous custom_summary value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "object", "properties": { "example": { "type": "string", "description": "Example output illustrating the desired summary style." }, "instructions": { "type": "string", "description": "Instructions to follow when generating the summary." } }, "additionalProperties": false, "description": "Instructions and optional example for generating summaries from meetings using this template." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "tags": { "description": "Commit only if the previous tags value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "sort_order": { "description": "Commit only if the previous sort_order value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "number", "description": "Relative ordering value used to display templates." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] } } } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_meetingtemplate_example", "data": { "name": "Customer project kickoff" } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:MeetingTemplate record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "name": { "type": "string", "description": "Name used to select this meeting template." }, "agenda": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." }, "subtopics": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." } }, "additionalProperties": false }, "description": "Second-level discussion topics; no deeper nesting is supported." } }, "additionalProperties": false }, "description": "Default two-level agenda to use when applying this template." }, "custom_summary": { "type": "object", "properties": { "example": { "type": "string", "description": "Example output illustrating the desired summary style." }, "instructions": { "type": "string", "description": "Instructions to follow when generating the summary." } }, "additionalProperties": false, "description": "Instructions and optional example for generating summaries from meetings using this template." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, "sort_order": { "type": "number", "description": "Relative ordering value used to display templates." } }, "required": [ "name" ], "additionalProperties": false, "description": "The record's fields.", "title": "MeetingTemplate" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "MeetingTemplateRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_meetingtemplate_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "Customer project kickoff", "agenda": [ { "id": "objectives", "name": "Objectives", "status": "None" }, { "id": "next-steps", "name": "Next steps", "status": "None" } ], "custom_summary": { "instructions": "Summarize decisions, action owners and due dates." } } } } ] } ``` --- # Upsert meeting template Create or update a meeting template by a permanent external reference. Matching is exact within the workspace, resource type and ownership scope. Supplied fields replace their values; omitted fields stay unchanged. Deleted records are not recreated. POST https://api.brigg.app/v1/operations/meetings.UpsertMeetingTemplate ## Access & visibility Allow `meetings.UpsertMeetingTemplate` on your API key. Resource read permissions: `core:MeetingTemplate`. Resource write permissions: `core:MeetingTemplate`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `data` | [MeetingTemplate](#meetingtemplate-request-data) | Yes | The record's fields. | | `private` | boolean | No | Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance. | | `external_ref` | [object](#request-external-ref) | Yes | Permanent, case-sensitive source identity within this workspace, resource type and private/workspace scope. It is independent of API key rotation and retry receipt expiry. | ### MeetingTemplate · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Name used to select this meeting template. | | `agenda` | array of [object](#request-data-agenda) | No | Default two-level agenda to use when applying this template. | | `custom_summary` | [object](#request-data-custom-summary) | No | Instructions and optional example for generating summaries from meetings using this template. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | | `sort_order` | number | No | Relative ordering value used to display templates. | ### request.data.agenda[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | | `subtopics` | array of [object](#request-data-agenda-subtopics) | No | Second-level discussion topics; no deeper nesting is supported. | ### request.data.agenda[].subtopics[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | ### request.data.custom_summary | Field | Type | Required | Description | | --- | --- | --- | --- | | `example` | string | No | Example output illustrating the desired summary style. | | `instructions` | string | No | Instructions to follow when generating the summary. | ### request.external_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `namespace` | string | Yes | A stable name for the source system, such as crm-production. At least 1 character. | | `id` | string | Yes | The record ID in that source system. At least 1 character. | ## Sync with a permanent external reference Choose a stable `external_ref.namespace` for your source system and put its record ID in `external_ref.id`. Matching is case-sensitive and scoped to this workspace, resource type and private/workspace ownership. The reference survives API key replacement and the 30-day retry receipt window. It does not match records by email or name. Send the required create fields each time. A missing reference creates a record; an existing reference updates only supplied fields and preserves everything else. `created` tells you which happened. Use the same idempotency key when retrying a lost response and a new key for a later source change. Concurrent calls cannot create duplicate records. A deleted or inaccessible match is refused; the operation does not restore it or make a replacement. Use the returned `item.id` with the regular update operation when you need `unset` or a conditional `expected` edit. Changing `private` chooses a different ownership scope; it does not transfer an existing record. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [MeetingTemplateRecord](#meetingtemplaterecord-response-item) | Yes | The requested record, including its metadata and data fields. | | `created` | boolean | Yes | True when this external reference created a record; false when it matched an existing record. | ### MeetingTemplateRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:MeetingTemplate record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [MeetingTemplate](#meetingtemplate-response-item-data) | Yes | The record's fields. | ### MeetingTemplate · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Name used to select this meeting template. | | `agenda` | array of [object](#response-item-data-agenda) | No | Default two-level agenda to use when applying this template. | | `custom_summary` | [object](#response-item-data-custom-summary) | No | Instructions and optional example for generating summaries from meetings using this template. | | `tags` | array of string | No | Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs. | | `sort_order` | number | No | Relative ordering value used to display templates. | ### response.item.data.agenda[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | | `subtopics` | array of [object](#response-item-data-agenda-subtopics) | No | Second-level discussion topics; no deeper nesting is supported. | ### response.item.data.agenda[].subtopics[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | No | Stable identifier of this agenda topic or subtopic. | | `name` | string | No | Topic or subtopic title. | | `status` | string | No | Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive. Allowed: `"None"`, `"Touched"`, `"Partial"`, `"Full"`. | ### response.item.data.custom_summary | Field | Type | Required | Description | | --- | --- | --- | --- | | `example` | string | No | Example output illustrating the desired summary style. | | `instructions` | string | No | Instructions to follow when generating the summary. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List meeting templates](/developers/reference/meetings/ListMeetingTemplates) - [Get meeting template](/developers/reference/meetings/GetMeetingTemplate) - [Create meeting template](/developers/reference/meetings/CreateMeetingTemplate) - [Update meeting template](/developers/reference/meetings/UpdateMeetingTemplate) - [Delete meeting template](/developers/reference/meetings/DeleteMeetingTemplate) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### First sync Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.UpsertMeetingTemplate' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "name": "Project kickoff", "agenda": [ { "id": "objectives", "name": "Objectives", "status": "None" }, { "id": "next-steps", "name": "Next steps", "status": "None" } ], "custom_summary": { "instructions": "Summarize decisions, action owners and due dates." } } }' ``` #### TypeScript ```typescript 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.UpsertMeetingTemplate", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "name": "Project kickoff", "agenda": [ { "id": "objectives", "name": "Objectives", "status": "None" }, { "id": "next-steps", "name": "Next steps", "status": "None" } ], "custom_summary": { "instructions": "Summarize decisions, action owners and due dates." } } }), }); 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 = { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "name": "Project kickoff", "agenda": [ { "id": "objectives", "name": "Objectives", "status": "None" }, { "id": "next-steps", "name": "Next steps", "status": "None" } ], "custom_summary": { "instructions": "Summarize decisions, action owners and due dates." } } } request = Request( "https://api.brigg.app/v1/operations/meetings.UpsertMeetingTemplate", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_meetingtemplate_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "Project kickoff", "agenda": [ { "id": "objectives", "name": "Objectives", "status": "None" }, { "id": "next-steps", "name": "Next steps", "status": "None" } ], "custom_summary": { "instructions": "Summarize decisions, action owners and due dates." } } }, "created": true } ``` ### Later sync The same external reference returns the same record ID. Use a new idempotency key for a later source change. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.UpsertMeetingTemplate' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "name": "Project kickoff", "agenda": [ { "id": "objectives", "name": "Objectives", "status": "None" }, { "id": "next-steps", "name": "Next steps", "status": "None" } ], "custom_summary": { "instructions": "Summarize decisions, action owners and due dates." } } }' ``` #### TypeScript ```typescript 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.UpsertMeetingTemplate", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "name": "Project kickoff", "agenda": [ { "id": "objectives", "name": "Objectives", "status": "None" }, { "id": "next-steps", "name": "Next steps", "status": "None" } ], "custom_summary": { "instructions": "Summarize decisions, action owners and due dates." } } }), }); 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 = { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "name": "Project kickoff", "agenda": [ { "id": "objectives", "name": "Objectives", "status": "None" }, { "id": "next-steps", "name": "Next steps", "status": "None" } ], "custom_summary": { "instructions": "Summarize decisions, action owners and due dates." } } } request = Request( "https://api.brigg.app/v1/operations/meetings.UpsertMeetingTemplate", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_meetingtemplate_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "Project kickoff", "agenda": [ { "id": "objectives", "name": "Objectives", "status": "None" }, { "id": "next-steps", "name": "Next steps", "status": "None" } ], "custom_summary": { "instructions": "Summarize decisions, action owners and due dates." } } }, "created": false } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "data": { "type": "object", "properties": { "name": { "type": "string", "description": "Name used to select this meeting template." }, "agenda": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." }, "subtopics": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." } }, "additionalProperties": false }, "description": "Second-level discussion topics; no deeper nesting is supported." } }, "additionalProperties": false }, "description": "Default two-level agenda to use when applying this template." }, "custom_summary": { "type": "object", "properties": { "example": { "type": "string", "description": "Example output illustrating the desired summary style." }, "instructions": { "type": "string", "description": "Instructions to follow when generating the summary." } }, "additionalProperties": false, "description": "Instructions and optional example for generating summaries from meetings using this template." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, "sort_order": { "type": "number", "description": "Relative ordering value used to display templates." } }, "required": [ "name" ], "additionalProperties": false, "description": "The record's fields.", "title": "MeetingTemplate" }, "private": { "type": "boolean", "description": "Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance." }, "external_ref": { "type": "object", "description": "Permanent, case-sensitive source identity within this workspace, resource type and private/workspace scope. It is independent of API key rotation and retry receipt expiry.", "properties": { "namespace": { "type": "string", "minLength": 1, "description": "A stable name for the source system, such as crm-production." }, "id": { "type": "string", "minLength": 1, "description": "The record ID in that source system." } }, "required": [ "namespace", "id" ], "additionalProperties": false } }, "required": [ "external_ref", "data" ], "additionalProperties": false, "examples": [ { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "name": "Project kickoff", "agenda": [ { "id": "objectives", "name": "Objectives", "status": "None" }, { "id": "next-steps", "name": "Next steps", "status": "None" } ], "custom_summary": { "instructions": "Summarize decisions, action owners and due dates." } } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:MeetingTemplate record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "name": { "type": "string", "description": "Name used to select this meeting template." }, "agenda": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." }, "subtopics": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable identifier of this agenda topic or subtopic." }, "name": { "type": "string", "description": "Topic or subtopic title." }, "status": { "type": "string", "enum": [ "None", "Touched", "Partial", "Full" ], "description": "Topic coverage: None = not covered, Touched = mentioned, Partial = partly covered, Full = covered. Values are case-sensitive." } }, "additionalProperties": false }, "description": "Second-level discussion topics; no deeper nesting is supported." } }, "additionalProperties": false }, "description": "Default two-level agenda to use when applying this template." }, "custom_summary": { "type": "object", "properties": { "example": { "type": "string", "description": "Example output illustrating the desired summary style." }, "instructions": { "type": "string", "description": "Instructions to follow when generating the summary." } }, "additionalProperties": false, "description": "Instructions and optional example for generating summaries from meetings using this template." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable tag keys, not labels. Use [List tag vocabularies](/developers/reference/customers/ListTagVocabularies) to find the vocabulary for this resource type and field, then [List tags](/developers/reference/customers/ListTags) for its key/label pairs." }, "sort_order": { "type": "number", "description": "Relative ordering value used to display templates." } }, "required": [ "name" ], "additionalProperties": false, "description": "The record's fields.", "title": "MeetingTemplate" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "MeetingTemplateRecord" }, "created": { "type": "boolean", "description": "True when this external reference created a record; false when it matched an existing record." } }, "required": [ "item", "created" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_meetingtemplate_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "name": "Project kickoff", "agenda": [ { "id": "objectives", "name": "Objectives", "status": "None" }, { "id": "next-steps", "name": "Next steps", "status": "None" } ], "custom_summary": { "instructions": "Summarize decisions, action owners and due dates." } } }, "created": true } ] } ``` --- # Set meeting summary emails Choose who receives the caller's automatic meeting-summary emails: all attendees, external attendees, colleagues only or nobody. POST https://api.brigg.app/v1/operations/meetings.SetMeetingSummaryEmails ## Access & visibility Allow `meetings.SetMeetingSummaryEmails` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `scope` | string | Yes | Automatic attendee-email audience for meetings hosted by the acting member: all includes external attendees, external means only people outside the workspace, internal means workspace colleagues only, and off disables attendee emails. This is a delivery preference, not meeting visibility. Allowed: `"all"`, `"external"`, `"internal"`, `"off"`. | ## Change the host's future delivery preference With member delegation, this updates the approved acting member's own preference, not a workspace-wide default. Automatic delivery reads the meeting host's preference when a summary is generated. This call saves a setting; it does not send old summaries, recall delivered messages or confirm any later delivery. The default attendee setting is off when no preference is stored. The host's own summary email has a separate setting: off here does not disable that personal copy. Review current preferences in Brigg Settings; this operation returns the newly saved value rather than the previous one. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `scope` | string | Yes | The saved attendee-email preference, matching the requested scope. It does not report a message send or delivery outcome. Allowed: `"all"`, `"external"`, `"internal"`, `"off"`. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | ## Next steps [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Email colleagues only External attendees will not receive automatic attendee emails under this setting. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.SetMeetingSummaryEmails' \ -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 '{ "scope": "internal" }' ``` #### 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.SetMeetingSummaryEmails", { 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({ "scope": "internal" }), }); 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 = { "scope": "internal" } request = Request( "https://api.brigg.app/v1/operations/meetings.SetMeetingSummaryEmails", 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 { "scope": "internal" } ``` ### Disable attendee emails The host's own summary email remains controlled separately. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.SetMeetingSummaryEmails' \ -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 '{ "scope": "off" }' ``` #### 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.SetMeetingSummaryEmails", { 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({ "scope": "off" }), }); 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 = { "scope": "off" } request = Request( "https://api.brigg.app/v1/operations/meetings.SetMeetingSummaryEmails", 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 { "scope": "off" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "scope": { "type": "string", "enum": [ "all", "external", "internal", "off" ], "description": "Automatic attendee-email audience for meetings hosted by the acting member: all includes external attendees, external means only people outside the workspace, internal means workspace colleagues only, and off disables attendee emails. This is a delivery preference, not meeting visibility." } }, "required": [ "scope" ], "additionalProperties": false, "examples": [ { "scope": "internal" } ] } ``` ```json-schema-response { "type": "object", "properties": { "scope": { "type": "string", "enum": [ "all", "external", "internal", "off" ], "description": "The saved attendee-email preference, matching the requested scope. It does not report a message send or delivery outcome." } }, "required": [ "scope" ], "additionalProperties": false, "examples": [ { "scope": "internal" } ] } ``` --- # List booking links List your booking links and upcoming confirmed bookings. Each link includes its public URL and availability settings. POST https://api.brigg.app/v1/operations/meetings.ListBookingLinks ## Access & visibility Allow `meetings.ListBookingLinks` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/permissions) ## Request No parameters. Send an empty JSON object (`{}`). ## Booking links and individual bookings A booking link belongs to the acting member and advertises availability in its IANA `timezone`. Availability times are local wall-clock times in that zone; confirmed bookings use numeric timestamps. Use [List booking links](/developers/reference/meetings/ListBookingLinks) to read both links (`items`) and their confirmed bookings starting in the next 366 days (`upcoming_bookings`). The link ID changes or deactivates the booking page. An individual booking ID cancels one confirmed appointment. Deactivating a link stops new bookings without cancelling appointments already made. A link with future bookings cannot be deleted; deactivate it or cancel those bookings first. Active links require a connected writable calendar. ## Response Returns **200 OK** with a JSON body. This operation has no continuation cursor. An empty `items` array means no matching visible results were returned. | Field | Type | Required | Description | | --- | --- | --- | --- | | `upcoming_bookings` | array of [object](#response-upcoming-bookings) | Yes | Confirmed bookings starting in the next 366 days across these links, separate from the link definitions. An empty array means no upcoming bookings were returned; inactive links can still have appointments. | | `items` | array of [Booking link](#booking-link-response-items) | Yes | Booking links owned by the acting member; upcoming bookings are returned separately. This operation has no cursor pagination. | ### response.upcoming_bookings[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Individual booking ID. Pass this to CancelBooking to cancel this appointment, not the link_id. | | `link_id` | string | Yes | Booking-link ID matching items[].id. Use it for link updates or deactivation, not to cancel one appointment. | | `start_at` | number | Yes | Booking start time in Unix milliseconds. | | `end_at` | number | Yes | Booking end time in Unix milliseconds. | | `timezone` | string | No | Invitee's IANA timezone, when recorded. start_at and end_at are absolute Unix millisecond timestamps; format them in the desired display zone. | | `invitee_name` | string | Yes | Name supplied by the person who booked the meeting. | | `invitee_email` | string | Yes | Email address of the person who booked the meeting. | | `note` | string or null | No | Optional note supplied by the invitee when booking. Null means no note was supplied. | ### Booking link · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Booking link ID. Use it to update or delete this link. | | `org_id` | string | Yes | Workspace that owns the link. | | `owner_account_id` | string | Yes | Member whose calendar supplies the available time slots. | | `slug` | string | Yes | Unique URL segment for this link within the workspace. | | `name` | string | Yes | Meeting name displayed to invitees. | | `description` | string or null | Yes | Introduction displayed on the booking page. | | `duration_minutes` | integer | Yes | Default meeting length in minutes; the shortest length when several are offered. | | `duration_options` | array of integer or null | Yes | Offered meeting lengths in minutes. Null means a fixed duration_minutes. | | `location_kind` | string | Yes | video creates a conference link; phone, in_person and custom use location_detail for instructions or an address. Allowed: `"video"`, `"phone"`, `"in_person"`, `"custom"`. | | `location_detail` | string or null | Yes | Address, phone instructions or other location details. | | `timezone` | string | Yes | IANA time zone used to interpret the weekly availability, for example Europe/Oslo. | | `availability` | [WeeklyAvailability](#weeklyavailability-response-items-availability) | Yes | Bookable local-time intervals by weekday. Missing or empty days are unavailable. | | `window_days` | integer | Yes | How many days into the future invitees can book. | | `min_notice_minutes` | integer | Yes | Minimum time before a meeting can start, in minutes. | | `buffer_before_minutes` | integer | Yes | Minutes reserved before each meeting. | | `buffer_after_minutes` | integer | Yes | Minutes reserved after each meeting. | | `max_per_day` | integer | Yes | Maximum bookings per day. Zero means no daily limit. | | `questions` | array of [object](#response-items-questions) or null | Yes | Additional questions shown to invitees. Null means no questions. | | `reminder_hours` | integer | Yes | Hours before the meeting to send a reminder. Zero disables reminders. | | `collect_phone` | boolean | Yes | Whether invitees are asked for a phone number. | | `active` | boolean | Yes | Whether invitees can make new bookings through this link. | | `created_at` | integer | Yes | Creation time in Unix milliseconds. | | `updated_at` | integer | Yes | Last change in Unix milliseconds. | | `url` | string | Yes | Public booking URL to share with invitees. Format: uri. | ### WeeklyAvailability · response.items[].availability | Field | Type | Required | Description | | --- | --- | --- | --- | | `mon` | array of [object](#response-items-availability-mon) | No | Monday availability intervals in the booking link's timezone. At most 6 items. | | `tue` | array of [object](#response-items-availability-tue) | No | Tuesday availability intervals in the booking link's timezone. At most 6 items. | | `wed` | array of [object](#response-items-availability-wed) | No | Wednesday availability intervals in the booking link's timezone. At most 6 items. | | `thu` | array of [object](#response-items-availability-thu) | No | Thursday availability intervals in the booking link's timezone. At most 6 items. | | `fri` | array of [object](#response-items-availability-fri) | No | Friday availability intervals in the booking link's timezone. At most 6 items. | | `sat` | array of [object](#response-items-availability-sat) | No | Saturday availability intervals in the booking link's timezone. At most 6 items. | | `sun` | array of [object](#response-items-availability-sun) | No | Sunday availability intervals in the booking link's timezone. At most 6 items. | ### response.items[].availability.mon[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `start` | string | Yes | Start of the interval. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | | `end` | string | Yes | End of the interval; must be later than its start. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | ### response.items[].availability.tue[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `start` | string | Yes | Start of the interval. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | | `end` | string | Yes | End of the interval; must be later than its start. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | ### response.items[].availability.wed[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `start` | string | Yes | Start of the interval. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | | `end` | string | Yes | End of the interval; must be later than its start. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | ### response.items[].availability.thu[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `start` | string | Yes | Start of the interval. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | | `end` | string | Yes | End of the interval; must be later than its start. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | ### response.items[].availability.fri[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `start` | string | Yes | Start of the interval. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | | `end` | string | Yes | End of the interval; must be later than its start. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | ### response.items[].availability.sat[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `start` | string | Yes | Start of the interval. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | | `end` | string | Yes | End of the interval; must be later than its start. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | ### response.items[].availability.sun[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `start` | string | Yes | Start of the interval. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | | `end` | string | Yes | End of the interval; must be later than its start. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | ### response.items[].questions[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable question key you choose, unique within this link, such as project_goal. Reuse it when editing that question; no create-record call is needed. At least 1 character. At most 40 characters. | | `label` | string | Yes | Text shown for this booking question or choice. At least 1 character. At most 200 characters. | | `kind` | string | Yes | Question control: text is a short answer, textarea a longer answer, select a choice from options, and checkbox a yes/no response. Allowed: `"text"`, `"textarea"`, `"select"`, `"checkbox"`. | | `required` | boolean | No | Whether the invitee must answer this booking question. | | `options` | array of string | No | Choices for a select question; at least one is required when kind=select. Omit for other controls. At least 1 item. At most 12 items. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 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. | ## Next steps - [List calendar connections](/developers/reference/meetings/ListCalendarConnections) - [Update booking link](/developers/reference/meetings/UpdateBookingLink) - [Cancel booking](/developers/reference/meetings/CancelBooking) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Links and their upcoming appointments Match upcoming_bookings[].link_id to items[].id; use the appointment's own id when cancelling one booking. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.ListBookingLinks' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Brigg-Act-As: $BRIGG_ACT_AS" \ --data-raw '{}' ``` #### 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 response = await fetch("https://api.brigg.app/v1/operations/meetings.ListBookingLinks", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Brigg-Act-As": actAs, }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/meetings.ListBookingLinks", 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"], }, 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 { "items": [ { "id": "bkl_example", "org_id": "o_example", "owner_account_id": "a_example", "slug": "project-introduction", "name": "Project introduction", "description": null, "duration_minutes": 30, "duration_options": null, "location_kind": "video", "location_detail": null, "timezone": "Europe/Oslo", "availability": { "mon": [ { "start": "09:00", "end": "17:00" } ] }, "window_days": 30, "min_notice_minutes": 240, "buffer_before_minutes": 0, "buffer_after_minutes": 0, "max_per_day": 0, "questions": null, "reminder_hours": 24, "collect_phone": false, "active": true, "created_at": 1794301200000, "updated_at": 1794301200000, "url": "https://example.com/book/project-introduction" } ], "upcoming_bookings": [ { "id": "bk_project_intro", "link_id": "bkl_example", "start_at": 1794823200000, "end_at": 1794825000000, "timezone": "Europe/Oslo", "invitee_name": "Alex Morgan", "invitee_email": "alex@example.com", "note": "Please bring the onboarding checklist." } ] } ``` ### This member has no booking links This is an authorized empty result for the acting member, not the workspace's complete link catalogue. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.ListBookingLinks' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Brigg-Act-As: $BRIGG_ACT_AS" \ --data-raw '{}' ``` #### 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 response = await fetch("https://api.brigg.app/v1/operations/meetings.ListBookingLinks", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Brigg-Act-As": actAs, }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/meetings.ListBookingLinks", 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"], }, 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 { "items": [], "upcoming_bookings": [] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": {}, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "upcoming_bookings": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Individual booking ID. Pass this to CancelBooking to cancel this appointment, not the link_id." }, "link_id": { "type": "string", "description": "Booking-link ID matching items[].id. Use it for link updates or deactivation, not to cancel one appointment." }, "start_at": { "type": "number", "description": "Booking start time in Unix milliseconds." }, "end_at": { "type": "number", "description": "Booking end time in Unix milliseconds." }, "timezone": { "type": "string", "description": "Invitee's IANA timezone, when recorded. start_at and end_at are absolute Unix millisecond timestamps; format them in the desired display zone." }, "invitee_name": { "type": "string", "description": "Name supplied by the person who booked the meeting." }, "invitee_email": { "type": "string", "description": "Email address of the person who booked the meeting." }, "note": { "type": [ "string", "null" ], "description": "Optional note supplied by the invitee when booking. Null means no note was supplied." } }, "required": [ "id", "link_id", "start_at", "end_at", "invitee_name", "invitee_email" ], "additionalProperties": false }, "description": "Confirmed bookings starting in the next 366 days across these links, separate from the link definitions. An empty array means no upcoming bookings were returned; inactive links can still have appointments." }, "items": { "type": "array", "items": { "title": "Booking link", "type": "object", "properties": { "id": { "type": "string", "description": "Booking link ID. Use it to update or delete this link." }, "org_id": { "type": "string", "description": "Workspace that owns the link." }, "owner_account_id": { "type": "string", "description": "Member whose calendar supplies the available time slots." }, "slug": { "type": "string", "description": "Unique URL segment for this link within the workspace." }, "name": { "type": "string", "description": "Meeting name displayed to invitees." }, "description": { "description": "Introduction displayed on the booking page.", "anyOf": [ { "type": "string", "description": "Introduction displayed on the booking page." }, { "type": "null" } ] }, "duration_minutes": { "type": "integer", "description": "Default meeting length in minutes; the shortest length when several are offered." }, "duration_options": { "description": "Offered meeting lengths in minutes. Null means a fixed duration_minutes.", "anyOf": [ { "type": "array", "items": { "type": "integer" }, "description": "Offered meeting lengths in minutes. Null means a fixed duration_minutes." }, { "type": "null" } ] }, "location_kind": { "type": "string", "enum": [ "video", "phone", "in_person", "custom" ], "description": "video creates a conference link; phone, in_person and custom use location_detail for instructions or an address." }, "location_detail": { "description": "Address, phone instructions or other location details.", "anyOf": [ { "type": "string", "description": "Address, phone instructions or other location details." }, { "type": "null" } ] }, "timezone": { "type": "string", "description": "IANA time zone used to interpret the weekly availability, for example Europe/Oslo." }, "availability": { "type": "object", "properties": { "mon": { "type": "array", "items": { "type": "object", "properties": { "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "Start of the interval." }, "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "End of the interval; must be later than its start." } }, "required": [ "start", "end" ], "additionalProperties": false }, "maxItems": 6, "description": "Monday availability intervals in the booking link's timezone." }, "tue": { "type": "array", "items": { "type": "object", "properties": { "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "Start of the interval." }, "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "End of the interval; must be later than its start." } }, "required": [ "start", "end" ], "additionalProperties": false }, "maxItems": 6, "description": "Tuesday availability intervals in the booking link's timezone." }, "wed": { "type": "array", "items": { "type": "object", "properties": { "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "Start of the interval." }, "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "End of the interval; must be later than its start." } }, "required": [ "start", "end" ], "additionalProperties": false }, "maxItems": 6, "description": "Wednesday availability intervals in the booking link's timezone." }, "thu": { "type": "array", "items": { "type": "object", "properties": { "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "Start of the interval." }, "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "End of the interval; must be later than its start." } }, "required": [ "start", "end" ], "additionalProperties": false }, "maxItems": 6, "description": "Thursday availability intervals in the booking link's timezone." }, "fri": { "type": "array", "items": { "type": "object", "properties": { "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "Start of the interval." }, "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "End of the interval; must be later than its start." } }, "required": [ "start", "end" ], "additionalProperties": false }, "maxItems": 6, "description": "Friday availability intervals in the booking link's timezone." }, "sat": { "type": "array", "items": { "type": "object", "properties": { "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "Start of the interval." }, "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "End of the interval; must be later than its start." } }, "required": [ "start", "end" ], "additionalProperties": false }, "maxItems": 6, "description": "Saturday availability intervals in the booking link's timezone." }, "sun": { "type": "array", "items": { "type": "object", "properties": { "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "Start of the interval." }, "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "End of the interval; must be later than its start." } }, "required": [ "start", "end" ], "additionalProperties": false }, "maxItems": 6, "description": "Sunday availability intervals in the booking link's timezone." } }, "additionalProperties": false, "$schema": "http://json-schema.org/draft-07/schema#", "title": "WeeklyAvailability", "description": "Bookable local-time intervals by weekday. Missing or empty days are unavailable." }, "window_days": { "type": "integer", "description": "How many days into the future invitees can book." }, "min_notice_minutes": { "type": "integer", "description": "Minimum time before a meeting can start, in minutes." }, "buffer_before_minutes": { "type": "integer", "description": "Minutes reserved before each meeting." }, "buffer_after_minutes": { "type": "integer", "description": "Minutes reserved after each meeting." }, "max_per_day": { "type": "integer", "description": "Maximum bookings per day. Zero means no daily limit." }, "questions": { "description": "Additional questions shown to invitees. Null means no questions.", "anyOf": [ { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "maxLength": 40, "description": "Stable question key you choose, unique within this link, such as project_goal. Reuse it when editing that question; no create-record call is needed." }, "label": { "type": "string", "minLength": 1, "maxLength": 200, "description": "Text shown for this booking question or choice." }, "kind": { "type": "string", "enum": [ "text", "textarea", "select", "checkbox" ], "description": "Question control: text is a short answer, textarea a longer answer, select a choice from options, and checkbox a yes/no response." }, "required": { "type": "boolean", "description": "Whether the invitee must answer this booking question." }, "options": { "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 120 }, "minItems": 1, "maxItems": 12, "description": "Choices for a select question; at least one is required when kind=select. Omit for other controls." } }, "required": [ "id", "label", "kind" ], "additionalProperties": false }, "maxItems": 5, "$schema": "http://json-schema.org/draft-07/schema#", "description": "Additional questions shown to invitees. Null means no questions." }, { "type": "null" } ] }, "reminder_hours": { "type": "integer", "description": "Hours before the meeting to send a reminder. Zero disables reminders." }, "collect_phone": { "type": "boolean", "description": "Whether invitees are asked for a phone number." }, "active": { "type": "boolean", "description": "Whether invitees can make new bookings through this link." }, "created_at": { "type": "integer", "description": "Creation time in Unix milliseconds." }, "updated_at": { "type": "integer", "description": "Last change in Unix milliseconds." }, "url": { "type": "string", "description": "Public booking URL to share with invitees.", "format": "uri" } }, "required": [ "id", "org_id", "owner_account_id", "slug", "name", "description", "duration_minutes", "duration_options", "location_kind", "location_detail", "timezone", "availability", "window_days", "min_notice_minutes", "buffer_before_minutes", "buffer_after_minutes", "max_per_day", "questions", "reminder_hours", "collect_phone", "active", "created_at", "updated_at", "url" ], "additionalProperties": false }, "description": "Booking links owned by the acting member; upcoming bookings are returned separately. This operation has no cursor pagination." } }, "required": [ "items", "upcoming_bookings" ], "additionalProperties": false, "examples": [ { "items": [ { "id": "bkl_example", "org_id": "o_example", "owner_account_id": "a_example", "slug": "project-introduction", "name": "Project introduction", "description": null, "duration_minutes": 30, "duration_options": null, "location_kind": "video", "location_detail": null, "timezone": "Europe/Oslo", "availability": { "mon": [ { "start": "09:00", "end": "17:00" } ] }, "window_days": 30, "min_notice_minutes": 240, "buffer_before_minutes": 0, "buffer_after_minutes": 0, "max_per_day": 0, "questions": null, "reminder_hours": 24, "collect_phone": false, "active": true, "created_at": 1794301200000, "updated_at": 1794301200000, "url": "https://example.com/book/project-introduction" } ], "upcoming_bookings": [ { "id": "bk_project_intro", "link_id": "bkl_example", "start_at": 1794823200000, "end_at": 1794825000000, "timezone": "Europe/Oslo", "invitee_name": "Alex Morgan", "invitee_email": "alex@example.com", "note": "Please bring the onboarding checklist." } ] } ] } ``` --- # Create booking link Create a personal booking page where invitees can choose a free slot on your calendar. Requires a connected calendar with permission to create events. POST https://api.brigg.app/v1/operations/meetings.CreateBookingLink ## Access & visibility Allow `meetings.CreateBookingLink` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `name` | string | Yes | Meeting name displayed on the public booking page. At least 1 character. At most 120 characters. | | `description` | string | No | Introduction displayed to invitees. Send an empty string to clear it. At most 2000 characters. | | `duration_minutes` | integer | No | Fixed meeting length in minutes. Supplying this alone clears any previous choice of lengths. duration_options takes precedence when both are supplied. Default: `30`. Range: 10 to 480. | | `duration_options` | array of integer | No | Offered lengths in minutes. One length makes a fixed-duration link; several let the invitee choose. The stored duration_minutes is the shortest offered length. At least 1 item. At most 4 items. | | `location_kind` | string | No | video creates a conference link; phone, in_person and custom use location_detail for instructions or an address. Allowed: `"video"`, `"phone"`, `"in_person"`, `"custom"`. Default: `"video"`. | | `location_detail` | string | No | Instructions for the chosen location, such as a phone number or street address. Send an empty string to clear them. At most 500 characters. | | `timezone` | string | No | An IANA time zone; refused invalid_timezone otherwise. Default: `"Europe/Oslo"`. | | `availability` | [object](#request-availability) | No | Complete weekly availability in the link's IANA timezone. Omitted or empty weekdays within this object are unavailable. This replaces the whole schedule, not only the listed days. | | `window_days` | integer | No | Number of days into the future an invitee can book. Default: `30`. Range: 1 to 90. | | `min_notice_minutes` | integer | No | Minimum notice required before a meeting starts, in minutes. Default: `240`. Range: 0 to 10080. | | `buffer_before_minutes` | integer | No | Minutes reserved before each meeting. Default: `0`. Range: 0 to 240. | | `buffer_after_minutes` | integer | No | Minutes reserved after each meeting. Default: `0`. Range: 0 to 240. | | `max_per_day` | integer | No | Maximum bookings in a day. Zero means no daily limit. Default: `0`. Range: 0 to 50. | | `questions` | array of [object](#request-questions) | No | Complete replacement question list. Send [] to remove all questions; omit the field on an update to preserve them. At most 5 items. | | `reminder_hours` | integer | No | Hours before a meeting to send a reminder. Zero disables reminders. Default: `24`. Range: 0 to 336. | | `collect_phone` | boolean | No | Whether the booking form asks invitees for a phone number. Default: `false`. | | `active` | boolean | No | Whether new bookings are accepted. False does not cancel confirmed appointments. Setting true requires the acting member's calendar write permission. Default: `true`. | ### request.availability | Field | Type | Required | Description | | --- | --- | --- | --- | | `mon` | array of [object](#request-availability-mon) | No | Monday availability intervals in the booking link's timezone. At most 6 items. | | `tue` | array of [object](#request-availability-tue) | No | Tuesday availability intervals in the booking link's timezone. At most 6 items. | | `wed` | array of [object](#request-availability-wed) | No | Wednesday availability intervals in the booking link's timezone. At most 6 items. | | `thu` | array of [object](#request-availability-thu) | No | Thursday availability intervals in the booking link's timezone. At most 6 items. | | `fri` | array of [object](#request-availability-fri) | No | Friday availability intervals in the booking link's timezone. At most 6 items. | | `sat` | array of [object](#request-availability-sat) | No | Saturday availability intervals in the booking link's timezone. At most 6 items. | | `sun` | array of [object](#request-availability-sun) | No | Sunday availability intervals in the booking link's timezone. At most 6 items. | ### request.availability.mon[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `start` | string | Yes | Start of the interval. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | | `end` | string | Yes | End of the interval; must be later than its start. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | ### request.availability.tue[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `start` | string | Yes | Start of the interval. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | | `end` | string | Yes | End of the interval; must be later than its start. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | ### request.availability.wed[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `start` | string | Yes | Start of the interval. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | | `end` | string | Yes | End of the interval; must be later than its start. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | ### request.availability.thu[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `start` | string | Yes | Start of the interval. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | | `end` | string | Yes | End of the interval; must be later than its start. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | ### request.availability.fri[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `start` | string | Yes | Start of the interval. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | | `end` | string | Yes | End of the interval; must be later than its start. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | ### request.availability.sat[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `start` | string | Yes | Start of the interval. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | | `end` | string | Yes | End of the interval; must be later than its start. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | ### request.availability.sun[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `start` | string | Yes | Start of the interval. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | | `end` | string | Yes | End of the interval; must be later than its start. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | ### request.questions[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable question key you choose, unique within this link, such as project_goal. Reuse it when editing that question; no create-record call is needed. At least 1 character. At most 40 characters. | | `label` | string | Yes | Text shown for this booking question or choice. At least 1 character. At most 200 characters. | | `kind` | string | Yes | Question control: text is a short answer, textarea a longer answer, select a choice from options, and checkbox a yes/no response. Allowed: `"text"`, `"textarea"`, `"select"`, `"checkbox"`. | | `required` | boolean | No | Whether the invitee must answer this booking question. | | `options` | array of string | No | Choices for a select question; at least one is required when kind=select. Omit for other controls. At least 1 item. At most 12 items. | ## Prepare the host's calendar first The approved acting member must connect a calendar with write access before creating a link, even when active=false. Creation defaults apply only here; later updates preserve omitted fields. The response's url is the public page to share with invitees. The URL alone does not guarantee there is an available slot: local availability, calendar conflicts, notice, buffers and booking limits all affect the choices shown. ## Booking links and individual bookings A booking link belongs to the acting member and advertises availability in its IANA `timezone`. Availability times are local wall-clock times in that zone; confirmed bookings use numeric timestamps. Use [List booking links](/developers/reference/meetings/ListBookingLinks) to read both links (`items`) and their confirmed bookings starting in the next 366 days (`upcoming_bookings`). The link ID changes or deactivates the booking page. An individual booking ID cancels one confirmed appointment. Deactivating a link stops new bookings without cancelling appointments already made. A link with future bookings cannot be deleted; deactivate it or cancel those bookings first. Active links require a connected writable calendar. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `link` | [BookingLink](#bookinglink-response-link) | Yes | The link row plus its public url. | ### BookingLink · response.link | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Booking link ID. Use it to update or delete this link. | | `org_id` | string | Yes | Workspace that owns the link. | | `owner_account_id` | string | Yes | Member whose calendar supplies the available time slots. | | `slug` | string | Yes | Unique URL segment for this link within the workspace. | | `name` | string | Yes | Meeting name displayed to invitees. | | `description` | string or null | Yes | Introduction displayed on the booking page. | | `duration_minutes` | integer | Yes | Default meeting length in minutes; the shortest length when several are offered. | | `duration_options` | array of integer or null | Yes | Offered meeting lengths in minutes. Null means a fixed duration_minutes. | | `location_kind` | string | Yes | video creates a conference link; phone, in_person and custom use location_detail for instructions or an address. Allowed: `"video"`, `"phone"`, `"in_person"`, `"custom"`. | | `location_detail` | string or null | Yes | Address, phone instructions or other location details. | | `timezone` | string | Yes | IANA time zone used to interpret the weekly availability, for example Europe/Oslo. | | `availability` | [WeeklyAvailability](#weeklyavailability-response-link-availability) | Yes | Bookable local-time intervals by weekday. Missing or empty days are unavailable. | | `window_days` | integer | Yes | How many days into the future invitees can book. | | `min_notice_minutes` | integer | Yes | Minimum time before a meeting can start, in minutes. | | `buffer_before_minutes` | integer | Yes | Minutes reserved before each meeting. | | `buffer_after_minutes` | integer | Yes | Minutes reserved after each meeting. | | `max_per_day` | integer | Yes | Maximum bookings per day. Zero means no daily limit. | | `questions` | array of [object](#response-link-questions) or null | Yes | Additional questions shown to invitees. Null means no questions. | | `reminder_hours` | integer | Yes | Hours before the meeting to send a reminder. Zero disables reminders. | | `collect_phone` | boolean | Yes | Whether invitees are asked for a phone number. | | `active` | boolean | Yes | Whether invitees can make new bookings through this link. | | `created_at` | integer | Yes | Creation time in Unix milliseconds. | | `updated_at` | integer | Yes | Last change in Unix milliseconds. | | `url` | string | Yes | Public booking URL to share with invitees. Format: uri. | ### WeeklyAvailability · response.link.availability | Field | Type | Required | Description | | --- | --- | --- | --- | | `mon` | array of [object](#response-link-availability-mon) | No | Monday availability intervals in the booking link's timezone. At most 6 items. | | `tue` | array of [object](#response-link-availability-tue) | No | Tuesday availability intervals in the booking link's timezone. At most 6 items. | | `wed` | array of [object](#response-link-availability-wed) | No | Wednesday availability intervals in the booking link's timezone. At most 6 items. | | `thu` | array of [object](#response-link-availability-thu) | No | Thursday availability intervals in the booking link's timezone. At most 6 items. | | `fri` | array of [object](#response-link-availability-fri) | No | Friday availability intervals in the booking link's timezone. At most 6 items. | | `sat` | array of [object](#response-link-availability-sat) | No | Saturday availability intervals in the booking link's timezone. At most 6 items. | | `sun` | array of [object](#response-link-availability-sun) | No | Sunday availability intervals in the booking link's timezone. At most 6 items. | ### response.link.availability.mon[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `start` | string | Yes | Start of the interval. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | | `end` | string | Yes | End of the interval; must be later than its start. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | ### response.link.availability.tue[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `start` | string | Yes | Start of the interval. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | | `end` | string | Yes | End of the interval; must be later than its start. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | ### response.link.availability.wed[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `start` | string | Yes | Start of the interval. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | | `end` | string | Yes | End of the interval; must be later than its start. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | ### response.link.availability.thu[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `start` | string | Yes | Start of the interval. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | | `end` | string | Yes | End of the interval; must be later than its start. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | ### response.link.availability.fri[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `start` | string | Yes | Start of the interval. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | | `end` | string | Yes | End of the interval; must be later than its start. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | ### response.link.availability.sat[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `start` | string | Yes | Start of the interval. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | | `end` | string | Yes | End of the interval; must be later than its start. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | ### response.link.availability.sun[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `start` | string | Yes | Start of the interval. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | | `end` | string | Yes | End of the interval; must be later than its start. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | ### response.link.questions[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable question key you choose, unique within this link, such as project_goal. Reuse it when editing that question; no create-record call is needed. At least 1 character. At most 40 characters. | | `label` | string | Yes | Text shown for this booking question or choice. At least 1 character. At most 200 characters. | | `kind` | string | Yes | Question control: text is a short answer, textarea a longer answer, select a choice from options, and checkbox a yes/no response. Allowed: `"text"`, `"textarea"`, `"select"`, `"checkbox"`. | | `required` | boolean | No | Whether the invitee must answer this booking question. | | `options` | array of string | No | Choices for a select question; at least one is required when kind=select. Omit for other controls. At least 1 item. At most 12 items. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | | 409 | `needs_auth` | Connect a calendar and grant calendar write access in Brigg. | | 422 | `invalid_timezone` | Use a valid IANA time zone. | ## Next steps - [List booking links](/developers/reference/meetings/ListBookingLinks) - [List calendar connections](/developers/reference/meetings/ListCalendarConnections) - [Update booking link](/developers/reference/meetings/UpdateBookingLink) - [Cancel booking](/developers/reference/meetings/CancelBooking) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.CreateBookingLink' \ -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 '{ "name": "Project introduction", "duration_minutes": 30, "location_kind": "video", "timezone": "Europe/Oslo", "availability": { "mon": [ { "start": "09:00", "end": "17:00" } ] } }' ``` #### 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.CreateBookingLink", { 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({ "name": "Project introduction", "duration_minutes": 30, "location_kind": "video", "timezone": "Europe/Oslo", "availability": { "mon": [ { "start": "09:00", "end": "17:00" } ] } }), }); 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 = { "name": "Project introduction", "duration_minutes": 30, "location_kind": "video", "timezone": "Europe/Oslo", "availability": { "mon": [ { "start": "09:00", "end": "17:00" } ] } } request = Request( "https://api.brigg.app/v1/operations/meetings.CreateBookingLink", 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 { "link": { "id": "bkl_example", "org_id": "o_example", "owner_account_id": "a_example", "slug": "project-introduction", "name": "Project introduction", "description": null, "duration_minutes": 30, "duration_options": null, "location_kind": "video", "location_detail": null, "timezone": "Europe/Oslo", "availability": { "mon": [ { "start": "09:00", "end": "17:00" } ] }, "window_days": 30, "min_notice_minutes": 240, "buffer_before_minutes": 0, "buffer_after_minutes": 0, "max_per_day": 0, "questions": null, "reminder_hours": 24, "collect_phone": false, "active": true, "created_at": 1794301200000, "updated_at": 1794301200000, "url": "https://example.com/book/project-introduction" } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 120, "description": "Meeting name displayed on the public booking page." }, "description": { "type": "string", "maxLength": 2000, "description": "Introduction displayed to invitees. Send an empty string to clear it." }, "duration_minutes": { "type": "integer", "minimum": 10, "maximum": 480, "default": 30, "description": "Fixed meeting length in minutes. Supplying this alone clears any previous choice of lengths. duration_options takes precedence when both are supplied." }, "duration_options": { "type": "array", "items": { "type": "integer", "minimum": 10, "maximum": 480 }, "minItems": 1, "maxItems": 4, "description": "Offered lengths in minutes. One length makes a fixed-duration link; several let the invitee choose. The stored duration_minutes is the shortest offered length." }, "location_kind": { "type": "string", "enum": [ "video", "phone", "in_person", "custom" ], "default": "video", "description": "video creates a conference link; phone, in_person and custom use location_detail for instructions or an address." }, "location_detail": { "type": "string", "maxLength": 500, "description": "Instructions for the chosen location, such as a phone number or street address. Send an empty string to clear them." }, "timezone": { "type": "string", "default": "Europe/Oslo", "description": "An IANA time zone; refused invalid_timezone otherwise." }, "availability": { "type": "object", "properties": { "mon": { "type": "array", "items": { "type": "object", "properties": { "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "Start of the interval." }, "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "End of the interval; must be later than its start." } }, "required": [ "start", "end" ], "additionalProperties": false }, "maxItems": 6, "description": "Monday availability intervals in the booking link's timezone." }, "tue": { "type": "array", "items": { "type": "object", "properties": { "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "Start of the interval." }, "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "End of the interval; must be later than its start." } }, "required": [ "start", "end" ], "additionalProperties": false }, "maxItems": 6, "description": "Tuesday availability intervals in the booking link's timezone." }, "wed": { "type": "array", "items": { "type": "object", "properties": { "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "Start of the interval." }, "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "End of the interval; must be later than its start." } }, "required": [ "start", "end" ], "additionalProperties": false }, "maxItems": 6, "description": "Wednesday availability intervals in the booking link's timezone." }, "thu": { "type": "array", "items": { "type": "object", "properties": { "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "Start of the interval." }, "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "End of the interval; must be later than its start." } }, "required": [ "start", "end" ], "additionalProperties": false }, "maxItems": 6, "description": "Thursday availability intervals in the booking link's timezone." }, "fri": { "type": "array", "items": { "type": "object", "properties": { "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "Start of the interval." }, "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "End of the interval; must be later than its start." } }, "required": [ "start", "end" ], "additionalProperties": false }, "maxItems": 6, "description": "Friday availability intervals in the booking link's timezone." }, "sat": { "type": "array", "items": { "type": "object", "properties": { "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "Start of the interval." }, "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "End of the interval; must be later than its start." } }, "required": [ "start", "end" ], "additionalProperties": false }, "maxItems": 6, "description": "Saturday availability intervals in the booking link's timezone." }, "sun": { "type": "array", "items": { "type": "object", "properties": { "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "Start of the interval." }, "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "End of the interval; must be later than its start." } }, "required": [ "start", "end" ], "additionalProperties": false }, "maxItems": 6, "description": "Sunday availability intervals in the booking link's timezone." } }, "additionalProperties": false, "description": "Complete weekly availability in the link's IANA timezone. Omitted or empty weekdays within this object are unavailable. This replaces the whole schedule, not only the listed days." }, "window_days": { "type": "integer", "minimum": 1, "maximum": 90, "default": 30, "description": "Number of days into the future an invitee can book." }, "min_notice_minutes": { "type": "integer", "minimum": 0, "maximum": 10080, "default": 240, "description": "Minimum notice required before a meeting starts, in minutes." }, "buffer_before_minutes": { "type": "integer", "minimum": 0, "maximum": 240, "default": 0, "description": "Minutes reserved before each meeting." }, "buffer_after_minutes": { "type": "integer", "minimum": 0, "maximum": 240, "default": 0, "description": "Minutes reserved after each meeting." }, "max_per_day": { "type": "integer", "minimum": 0, "maximum": 50, "default": 0, "description": "Maximum bookings in a day. Zero means no daily limit." }, "questions": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "maxLength": 40, "description": "Stable question key you choose, unique within this link, such as project_goal. Reuse it when editing that question; no create-record call is needed." }, "label": { "type": "string", "minLength": 1, "maxLength": 200, "description": "Text shown for this booking question or choice." }, "kind": { "type": "string", "enum": [ "text", "textarea", "select", "checkbox" ], "description": "Question control: text is a short answer, textarea a longer answer, select a choice from options, and checkbox a yes/no response." }, "required": { "type": "boolean", "description": "Whether the invitee must answer this booking question." }, "options": { "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 120 }, "minItems": 1, "maxItems": 12, "description": "Choices for a select question; at least one is required when kind=select. Omit for other controls." } }, "required": [ "id", "label", "kind" ], "additionalProperties": false }, "maxItems": 5, "description": "Complete replacement question list. Send [] to remove all questions; omit the field on an update to preserve them." }, "reminder_hours": { "type": "integer", "minimum": 0, "maximum": 336, "default": 24, "description": "Hours before a meeting to send a reminder. Zero disables reminders." }, "collect_phone": { "type": "boolean", "default": false, "description": "Whether the booking form asks invitees for a phone number." }, "active": { "type": "boolean", "default": true, "description": "Whether new bookings are accepted. False does not cancel confirmed appointments. Setting true requires the acting member's calendar write permission." } }, "required": [ "name" ], "additionalProperties": false, "examples": [ { "name": "Project introduction", "duration_minutes": 30, "location_kind": "video", "timezone": "Europe/Oslo", "availability": { "mon": [ { "start": "09:00", "end": "17:00" } ] } } ] } ``` ```json-schema-response { "type": "object", "properties": { "link": { "description": "The link row plus its public url.", "title": "BookingLink", "type": "object", "properties": { "id": { "type": "string", "description": "Booking link ID. Use it to update or delete this link." }, "org_id": { "type": "string", "description": "Workspace that owns the link." }, "owner_account_id": { "type": "string", "description": "Member whose calendar supplies the available time slots." }, "slug": { "type": "string", "description": "Unique URL segment for this link within the workspace." }, "name": { "type": "string", "description": "Meeting name displayed to invitees." }, "description": { "description": "Introduction displayed on the booking page.", "anyOf": [ { "type": "string", "description": "Introduction displayed on the booking page." }, { "type": "null" } ] }, "duration_minutes": { "type": "integer", "description": "Default meeting length in minutes; the shortest length when several are offered." }, "duration_options": { "description": "Offered meeting lengths in minutes. Null means a fixed duration_minutes.", "anyOf": [ { "type": "array", "items": { "type": "integer" }, "description": "Offered meeting lengths in minutes. Null means a fixed duration_minutes." }, { "type": "null" } ] }, "location_kind": { "type": "string", "enum": [ "video", "phone", "in_person", "custom" ], "description": "video creates a conference link; phone, in_person and custom use location_detail for instructions or an address." }, "location_detail": { "description": "Address, phone instructions or other location details.", "anyOf": [ { "type": "string", "description": "Address, phone instructions or other location details." }, { "type": "null" } ] }, "timezone": { "type": "string", "description": "IANA time zone used to interpret the weekly availability, for example Europe/Oslo." }, "availability": { "type": "object", "properties": { "mon": { "type": "array", "items": { "type": "object", "properties": { "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "Start of the interval." }, "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "End of the interval; must be later than its start." } }, "required": [ "start", "end" ], "additionalProperties": false }, "maxItems": 6, "description": "Monday availability intervals in the booking link's timezone." }, "tue": { "type": "array", "items": { "type": "object", "properties": { "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "Start of the interval." }, "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "End of the interval; must be later than its start." } }, "required": [ "start", "end" ], "additionalProperties": false }, "maxItems": 6, "description": "Tuesday availability intervals in the booking link's timezone." }, "wed": { "type": "array", "items": { "type": "object", "properties": { "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "Start of the interval." }, "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "End of the interval; must be later than its start." } }, "required": [ "start", "end" ], "additionalProperties": false }, "maxItems": 6, "description": "Wednesday availability intervals in the booking link's timezone." }, "thu": { "type": "array", "items": { "type": "object", "properties": { "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "Start of the interval." }, "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "End of the interval; must be later than its start." } }, "required": [ "start", "end" ], "additionalProperties": false }, "maxItems": 6, "description": "Thursday availability intervals in the booking link's timezone." }, "fri": { "type": "array", "items": { "type": "object", "properties": { "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "Start of the interval." }, "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "End of the interval; must be later than its start." } }, "required": [ "start", "end" ], "additionalProperties": false }, "maxItems": 6, "description": "Friday availability intervals in the booking link's timezone." }, "sat": { "type": "array", "items": { "type": "object", "properties": { "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "Start of the interval." }, "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "End of the interval; must be later than its start." } }, "required": [ "start", "end" ], "additionalProperties": false }, "maxItems": 6, "description": "Saturday availability intervals in the booking link's timezone." }, "sun": { "type": "array", "items": { "type": "object", "properties": { "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "Start of the interval." }, "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "End of the interval; must be later than its start." } }, "required": [ "start", "end" ], "additionalProperties": false }, "maxItems": 6, "description": "Sunday availability intervals in the booking link's timezone." } }, "additionalProperties": false, "$schema": "http://json-schema.org/draft-07/schema#", "title": "WeeklyAvailability", "description": "Bookable local-time intervals by weekday. Missing or empty days are unavailable." }, "window_days": { "type": "integer", "description": "How many days into the future invitees can book." }, "min_notice_minutes": { "type": "integer", "description": "Minimum time before a meeting can start, in minutes." }, "buffer_before_minutes": { "type": "integer", "description": "Minutes reserved before each meeting." }, "buffer_after_minutes": { "type": "integer", "description": "Minutes reserved after each meeting." }, "max_per_day": { "type": "integer", "description": "Maximum bookings per day. Zero means no daily limit." }, "questions": { "description": "Additional questions shown to invitees. Null means no questions.", "anyOf": [ { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "maxLength": 40, "description": "Stable question key you choose, unique within this link, such as project_goal. Reuse it when editing that question; no create-record call is needed." }, "label": { "type": "string", "minLength": 1, "maxLength": 200, "description": "Text shown for this booking question or choice." }, "kind": { "type": "string", "enum": [ "text", "textarea", "select", "checkbox" ], "description": "Question control: text is a short answer, textarea a longer answer, select a choice from options, and checkbox a yes/no response." }, "required": { "type": "boolean", "description": "Whether the invitee must answer this booking question." }, "options": { "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 120 }, "minItems": 1, "maxItems": 12, "description": "Choices for a select question; at least one is required when kind=select. Omit for other controls." } }, "required": [ "id", "label", "kind" ], "additionalProperties": false }, "maxItems": 5, "$schema": "http://json-schema.org/draft-07/schema#", "description": "Additional questions shown to invitees. Null means no questions." }, { "type": "null" } ] }, "reminder_hours": { "type": "integer", "description": "Hours before the meeting to send a reminder. Zero disables reminders." }, "collect_phone": { "type": "boolean", "description": "Whether invitees are asked for a phone number." }, "active": { "type": "boolean", "description": "Whether invitees can make new bookings through this link." }, "created_at": { "type": "integer", "description": "Creation time in Unix milliseconds." }, "updated_at": { "type": "integer", "description": "Last change in Unix milliseconds." }, "url": { "type": "string", "description": "Public booking URL to share with invitees.", "format": "uri" } }, "required": [ "id", "org_id", "owner_account_id", "slug", "name", "description", "duration_minutes", "duration_options", "location_kind", "location_detail", "timezone", "availability", "window_days", "min_notice_minutes", "buffer_before_minutes", "buffer_after_minutes", "max_per_day", "questions", "reminder_hours", "collect_phone", "active", "created_at", "updated_at", "url" ], "additionalProperties": false } }, "required": [ "link" ], "additionalProperties": false, "examples": [ { "link": { "id": "bkl_example", "org_id": "o_example", "owner_account_id": "a_example", "slug": "project-introduction", "name": "Project introduction", "description": null, "duration_minutes": 30, "duration_options": null, "location_kind": "video", "location_detail": null, "timezone": "Europe/Oslo", "availability": { "mon": [ { "start": "09:00", "end": "17:00" } ] }, "window_days": 30, "min_notice_minutes": 240, "buffer_before_minutes": 0, "buffer_after_minutes": 0, "max_per_day": 0, "questions": null, "reminder_hours": 24, "collect_phone": false, "active": true, "created_at": 1794301200000, "updated_at": 1794301200000, "url": "https://example.com/book/project-introduction" } } ] } ``` --- # Delete booking link Delete a booking link you own. Cancel its future confirmed bookings first, or deactivate the link to prevent new bookings. POST https://api.brigg.app/v1/operations/meetings.DeleteBookingLink ## Access & visibility Allow `meetings.DeleteBookingLink` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | Use a link's id from items. Check its upcoming bookings before deletion. [meetings.ListBookingLinks](/developers/reference/meetings/ListBookingLinks). At least 1 character. | ## Booking links and individual bookings A booking link belongs to the acting member and advertises availability in its IANA `timezone`. Availability times are local wall-clock times in that zone; confirmed bookings use numeric timestamps. Use [List booking links](/developers/reference/meetings/ListBookingLinks) to read both links (`items`) and their confirmed bookings starting in the next 366 days (`upcoming_bookings`). The link ID changes or deactivates the booking page. An individual booking ID cancels one confirmed appointment. Deactivating a link stops new bookings without cancelling appointments already made. A link with future bookings cannot be deleted; deactivate it or cancel those bookings first. Active links require a connected writable calendar. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | | 409 | `has_future_bookings` | Cancel the link's future bookings first, or deactivate the link instead. | ## Next steps - [List booking links](/developers/reference/meetings/ListBookingLinks) - [List calendar connections](/developers/reference/meetings/ListCalendarConnections) - [Update booking link](/developers/reference/meetings/UpdateBookingLink) - [Cancel booking](/developers/reference/meetings/CancelBooking) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.DeleteBookingLink' \ -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_example" }' ``` #### 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.DeleteBookingLink", { 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_example" }), }); 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_example" } request = Request( "https://api.brigg.app/v1/operations/meetings.DeleteBookingLink", 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 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Use a link's id from items. Check its upcoming bookings before deletion. [meetings.ListBookingLinks](/developers/reference/meetings/ListBookingLinks)." } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." } }, "required": [ "ok" ], "additionalProperties": false, "examples": [ { "ok": true } ] } ``` --- # Update booking link Change a booking link you own. Only supplied fields change. Activating a link requires calendar write permission; changing reminder timing also updates future bookings. POST https://api.brigg.app/v1/operations/meetings.UpdateBookingLink ## Access & visibility Allow `meetings.UpdateBookingLink` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | Use a link's id from items. This is not an individual booking ID. [meetings.ListBookingLinks](/developers/reference/meetings/ListBookingLinks). At least 1 character. | | `name` | string | No | Meeting name displayed on the public booking page. At least 1 character. At most 120 characters. | | `description` | string | No | Introduction displayed to invitees. Send an empty string to clear it. At most 2000 characters. | | `duration_minutes` | integer | No | Fixed meeting length in minutes. Supplying this alone clears any previous choice of lengths. duration_options takes precedence when both are supplied. Range: 10 to 480. | | `duration_options` | array of integer | No | Offered lengths in minutes. One length makes a fixed-duration link; several let the invitee choose. The stored duration_minutes is the shortest offered length. At least 1 item. At most 4 items. | | `location_kind` | string | No | video creates a conference link; phone, in_person and custom use location_detail for instructions or an address. Allowed: `"video"`, `"phone"`, `"in_person"`, `"custom"`. | | `location_detail` | string | No | Instructions for the chosen location, such as a phone number or street address. Send an empty string to clear them. At most 500 characters. | | `timezone` | string | No | An IANA time zone; refused invalid_timezone otherwise. | | `availability` | [object](#request-availability) | No | Complete weekly availability in the link's IANA timezone. Omitted or empty weekdays within this object are unavailable. This replaces the whole schedule, not only the listed days. | | `window_days` | integer | No | Number of days into the future an invitee can book. Range: 1 to 90. | | `min_notice_minutes` | integer | No | Minimum notice required before a meeting starts, in minutes. Range: 0 to 10080. | | `buffer_before_minutes` | integer | No | Minutes reserved before each meeting. Range: 0 to 240. | | `buffer_after_minutes` | integer | No | Minutes reserved after each meeting. Range: 0 to 240. | | `max_per_day` | integer | No | Maximum bookings in a day. Zero means no daily limit. Range: 0 to 50. | | `questions` | array of [object](#request-questions) | No | Complete replacement question list. Send [] to remove all questions; omit the field on an update to preserve them. At most 5 items. | | `reminder_hours` | integer | No | Hours before a meeting to send a reminder. Zero disables reminders. Range: 0 to 336. | | `collect_phone` | boolean | No | Whether the booking form asks invitees for a phone number. | | `active` | boolean | No | Whether new bookings are accepted. False does not cancel confirmed appointments. Setting true requires the acting member's calendar write permission. | ### request.availability | Field | Type | Required | Description | | --- | --- | --- | --- | | `mon` | array of [object](#request-availability-mon) | No | Monday availability intervals in the booking link's timezone. At most 6 items. | | `tue` | array of [object](#request-availability-tue) | No | Tuesday availability intervals in the booking link's timezone. At most 6 items. | | `wed` | array of [object](#request-availability-wed) | No | Wednesday availability intervals in the booking link's timezone. At most 6 items. | | `thu` | array of [object](#request-availability-thu) | No | Thursday availability intervals in the booking link's timezone. At most 6 items. | | `fri` | array of [object](#request-availability-fri) | No | Friday availability intervals in the booking link's timezone. At most 6 items. | | `sat` | array of [object](#request-availability-sat) | No | Saturday availability intervals in the booking link's timezone. At most 6 items. | | `sun` | array of [object](#request-availability-sun) | No | Sunday availability intervals in the booking link's timezone. At most 6 items. | ### request.availability.mon[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `start` | string | Yes | Start of the interval. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | | `end` | string | Yes | End of the interval; must be later than its start. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | ### request.availability.tue[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `start` | string | Yes | Start of the interval. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | | `end` | string | Yes | End of the interval; must be later than its start. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | ### request.availability.wed[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `start` | string | Yes | Start of the interval. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | | `end` | string | Yes | End of the interval; must be later than its start. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | ### request.availability.thu[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `start` | string | Yes | Start of the interval. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | | `end` | string | Yes | End of the interval; must be later than its start. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | ### request.availability.fri[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `start` | string | Yes | Start of the interval. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | | `end` | string | Yes | End of the interval; must be later than its start. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | ### request.availability.sat[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `start` | string | Yes | Start of the interval. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | | `end` | string | Yes | End of the interval; must be later than its start. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | ### request.availability.sun[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `start` | string | Yes | Start of the interval. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | | `end` | string | Yes | End of the interval; must be later than its start. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | ### request.questions[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable question key you choose, unique within this link, such as project_goal. Reuse it when editing that question; no create-record call is needed. At least 1 character. At most 40 characters. | | `label` | string | Yes | Text shown for this booking question or choice. At least 1 character. At most 200 characters. | | `kind` | string | Yes | Question control: text is a short answer, textarea a longer answer, select a choice from options, and checkbox a yes/no response. Allowed: `"text"`, `"textarea"`, `"select"`, `"checkbox"`. | | `required` | boolean | No | Whether the invitee must answer this booking question. | | `options` | array of string | No | Choices for a select question; at least one is required when kind=select. Omit for other controls. At least 1 item. At most 12 items. | ## Patch only what you intend to change Omitted top-level fields keep their current values; creation defaults are not reapplied. For example, {id, active:false} disables new bookings without changing duration, availability or reminders. Read the returned link for the complete saved configuration. Supplying availability replaces the entire weekly schedule, and questions replaces the entire question list. Include entries you want to retain. Empty description and location_detail strings clear those values. Changing reminder_hours also reschedules reminders for existing future bookings; it does not cancel those bookings. ## Booking links and individual bookings A booking link belongs to the acting member and advertises availability in its IANA `timezone`. Availability times are local wall-clock times in that zone; confirmed bookings use numeric timestamps. Use [List booking links](/developers/reference/meetings/ListBookingLinks) to read both links (`items`) and their confirmed bookings starting in the next 366 days (`upcoming_bookings`). The link ID changes or deactivates the booking page. An individual booking ID cancels one confirmed appointment. Deactivating a link stops new bookings without cancelling appointments already made. A link with future bookings cannot be deleted; deactivate it or cancel those bookings first. Active links require a connected writable calendar. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `link` | [BookingLink](#bookinglink-response-link) | Yes | The link row plus its public url. | ### BookingLink · response.link | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Booking link ID. Use it to update or delete this link. | | `org_id` | string | Yes | Workspace that owns the link. | | `owner_account_id` | string | Yes | Member whose calendar supplies the available time slots. | | `slug` | string | Yes | Unique URL segment for this link within the workspace. | | `name` | string | Yes | Meeting name displayed to invitees. | | `description` | string or null | Yes | Introduction displayed on the booking page. | | `duration_minutes` | integer | Yes | Default meeting length in minutes; the shortest length when several are offered. | | `duration_options` | array of integer or null | Yes | Offered meeting lengths in minutes. Null means a fixed duration_minutes. | | `location_kind` | string | Yes | video creates a conference link; phone, in_person and custom use location_detail for instructions or an address. Allowed: `"video"`, `"phone"`, `"in_person"`, `"custom"`. | | `location_detail` | string or null | Yes | Address, phone instructions or other location details. | | `timezone` | string | Yes | IANA time zone used to interpret the weekly availability, for example Europe/Oslo. | | `availability` | [WeeklyAvailability](#weeklyavailability-response-link-availability) | Yes | Bookable local-time intervals by weekday. Missing or empty days are unavailable. | | `window_days` | integer | Yes | How many days into the future invitees can book. | | `min_notice_minutes` | integer | Yes | Minimum time before a meeting can start, in minutes. | | `buffer_before_minutes` | integer | Yes | Minutes reserved before each meeting. | | `buffer_after_minutes` | integer | Yes | Minutes reserved after each meeting. | | `max_per_day` | integer | Yes | Maximum bookings per day. Zero means no daily limit. | | `questions` | array of [object](#response-link-questions) or null | Yes | Additional questions shown to invitees. Null means no questions. | | `reminder_hours` | integer | Yes | Hours before the meeting to send a reminder. Zero disables reminders. | | `collect_phone` | boolean | Yes | Whether invitees are asked for a phone number. | | `active` | boolean | Yes | Whether invitees can make new bookings through this link. | | `created_at` | integer | Yes | Creation time in Unix milliseconds. | | `updated_at` | integer | Yes | Last change in Unix milliseconds. | | `url` | string | Yes | Public booking URL to share with invitees. Format: uri. | ### WeeklyAvailability · response.link.availability | Field | Type | Required | Description | | --- | --- | --- | --- | | `mon` | array of [object](#response-link-availability-mon) | No | Monday availability intervals in the booking link's timezone. At most 6 items. | | `tue` | array of [object](#response-link-availability-tue) | No | Tuesday availability intervals in the booking link's timezone. At most 6 items. | | `wed` | array of [object](#response-link-availability-wed) | No | Wednesday availability intervals in the booking link's timezone. At most 6 items. | | `thu` | array of [object](#response-link-availability-thu) | No | Thursday availability intervals in the booking link's timezone. At most 6 items. | | `fri` | array of [object](#response-link-availability-fri) | No | Friday availability intervals in the booking link's timezone. At most 6 items. | | `sat` | array of [object](#response-link-availability-sat) | No | Saturday availability intervals in the booking link's timezone. At most 6 items. | | `sun` | array of [object](#response-link-availability-sun) | No | Sunday availability intervals in the booking link's timezone. At most 6 items. | ### response.link.availability.mon[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `start` | string | Yes | Start of the interval. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | | `end` | string | Yes | End of the interval; must be later than its start. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | ### response.link.availability.tue[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `start` | string | Yes | Start of the interval. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | | `end` | string | Yes | End of the interval; must be later than its start. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | ### response.link.availability.wed[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `start` | string | Yes | Start of the interval. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | | `end` | string | Yes | End of the interval; must be later than its start. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | ### response.link.availability.thu[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `start` | string | Yes | Start of the interval. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | | `end` | string | Yes | End of the interval; must be later than its start. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | ### response.link.availability.fri[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `start` | string | Yes | Start of the interval. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | | `end` | string | Yes | End of the interval; must be later than its start. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | ### response.link.availability.sat[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `start` | string | Yes | Start of the interval. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | | `end` | string | Yes | End of the interval; must be later than its start. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | ### response.link.availability.sun[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `start` | string | Yes | Start of the interval. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | | `end` | string | Yes | End of the interval; must be later than its start. Pattern: `^([01]\d\|2[0-3]):[0-5]\d$`. | ### response.link.questions[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable question key you choose, unique within this link, such as project_goal. Reuse it when editing that question; no create-record call is needed. At least 1 character. At most 40 characters. | | `label` | string | Yes | Text shown for this booking question or choice. At least 1 character. At most 200 characters. | | `kind` | string | Yes | Question control: text is a short answer, textarea a longer answer, select a choice from options, and checkbox a yes/no response. Allowed: `"text"`, `"textarea"`, `"select"`, `"checkbox"`. | | `required` | boolean | No | Whether the invitee must answer this booking question. | | `options` | array of string | No | Choices for a select question; at least one is required when kind=select. Omit for other controls. At least 1 item. At most 12 items. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | | 409 | `needs_auth` | Grant calendar write access before activating the link. | | 422 | `invalid_timezone` | Use a valid IANA time zone. | ## Next steps - [List booking links](/developers/reference/meetings/ListBookingLinks) - [List calendar connections](/developers/reference/meetings/ListCalendarConnections) - [Cancel booking](/developers/reference/meetings/CancelBooking) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.UpdateBookingLink' \ -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": "bkl_example", "active": false }' ``` #### 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.UpdateBookingLink", { 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": "bkl_example", "active": false }), }); 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": "bkl_example", "active": False } request = Request( "https://api.brigg.app/v1/operations/meetings.UpdateBookingLink", 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 { "link": { "id": "bkl_example", "org_id": "o_example", "owner_account_id": "a_example", "slug": "project-introduction", "name": "Project introduction", "description": null, "duration_minutes": 30, "duration_options": null, "location_kind": "video", "location_detail": null, "timezone": "Europe/Oslo", "availability": { "mon": [ { "start": "09:00", "end": "17:00" } ] }, "window_days": 30, "min_notice_minutes": 240, "buffer_before_minutes": 0, "buffer_after_minutes": 0, "max_per_day": 0, "questions": null, "reminder_hours": 24, "collect_phone": false, "active": false, "created_at": 1794301200000, "updated_at": 1794301200000, "url": "https://example.com/book/project-introduction" } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Use a link's id from items. This is not an individual booking ID. [meetings.ListBookingLinks](/developers/reference/meetings/ListBookingLinks)." }, "name": { "type": "string", "minLength": 1, "maxLength": 120, "description": "Meeting name displayed on the public booking page." }, "description": { "type": "string", "maxLength": 2000, "description": "Introduction displayed to invitees. Send an empty string to clear it." }, "duration_minutes": { "type": "integer", "minimum": 10, "maximum": 480, "description": "Fixed meeting length in minutes. Supplying this alone clears any previous choice of lengths. duration_options takes precedence when both are supplied." }, "duration_options": { "type": "array", "items": { "type": "integer", "minimum": 10, "maximum": 480 }, "minItems": 1, "maxItems": 4, "description": "Offered lengths in minutes. One length makes a fixed-duration link; several let the invitee choose. The stored duration_minutes is the shortest offered length." }, "location_kind": { "type": "string", "enum": [ "video", "phone", "in_person", "custom" ], "description": "video creates a conference link; phone, in_person and custom use location_detail for instructions or an address." }, "location_detail": { "type": "string", "maxLength": 500, "description": "Instructions for the chosen location, such as a phone number or street address. Send an empty string to clear them." }, "timezone": { "type": "string", "description": "An IANA time zone; refused invalid_timezone otherwise." }, "availability": { "type": "object", "properties": { "mon": { "type": "array", "items": { "type": "object", "properties": { "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "Start of the interval." }, "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "End of the interval; must be later than its start." } }, "required": [ "start", "end" ], "additionalProperties": false }, "maxItems": 6, "description": "Monday availability intervals in the booking link's timezone." }, "tue": { "type": "array", "items": { "type": "object", "properties": { "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "Start of the interval." }, "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "End of the interval; must be later than its start." } }, "required": [ "start", "end" ], "additionalProperties": false }, "maxItems": 6, "description": "Tuesday availability intervals in the booking link's timezone." }, "wed": { "type": "array", "items": { "type": "object", "properties": { "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "Start of the interval." }, "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "End of the interval; must be later than its start." } }, "required": [ "start", "end" ], "additionalProperties": false }, "maxItems": 6, "description": "Wednesday availability intervals in the booking link's timezone." }, "thu": { "type": "array", "items": { "type": "object", "properties": { "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "Start of the interval." }, "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "End of the interval; must be later than its start." } }, "required": [ "start", "end" ], "additionalProperties": false }, "maxItems": 6, "description": "Thursday availability intervals in the booking link's timezone." }, "fri": { "type": "array", "items": { "type": "object", "properties": { "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "Start of the interval." }, "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "End of the interval; must be later than its start." } }, "required": [ "start", "end" ], "additionalProperties": false }, "maxItems": 6, "description": "Friday availability intervals in the booking link's timezone." }, "sat": { "type": "array", "items": { "type": "object", "properties": { "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "Start of the interval." }, "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "End of the interval; must be later than its start." } }, "required": [ "start", "end" ], "additionalProperties": false }, "maxItems": 6, "description": "Saturday availability intervals in the booking link's timezone." }, "sun": { "type": "array", "items": { "type": "object", "properties": { "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "Start of the interval." }, "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "End of the interval; must be later than its start." } }, "required": [ "start", "end" ], "additionalProperties": false }, "maxItems": 6, "description": "Sunday availability intervals in the booking link's timezone." } }, "additionalProperties": false, "description": "Complete weekly availability in the link's IANA timezone. Omitted or empty weekdays within this object are unavailable. This replaces the whole schedule, not only the listed days." }, "window_days": { "type": "integer", "minimum": 1, "maximum": 90, "description": "Number of days into the future an invitee can book." }, "min_notice_minutes": { "type": "integer", "minimum": 0, "maximum": 10080, "description": "Minimum notice required before a meeting starts, in minutes." }, "buffer_before_minutes": { "type": "integer", "minimum": 0, "maximum": 240, "description": "Minutes reserved before each meeting." }, "buffer_after_minutes": { "type": "integer", "minimum": 0, "maximum": 240, "description": "Minutes reserved after each meeting." }, "max_per_day": { "type": "integer", "minimum": 0, "maximum": 50, "description": "Maximum bookings in a day. Zero means no daily limit." }, "questions": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "maxLength": 40, "description": "Stable question key you choose, unique within this link, such as project_goal. Reuse it when editing that question; no create-record call is needed." }, "label": { "type": "string", "minLength": 1, "maxLength": 200, "description": "Text shown for this booking question or choice." }, "kind": { "type": "string", "enum": [ "text", "textarea", "select", "checkbox" ], "description": "Question control: text is a short answer, textarea a longer answer, select a choice from options, and checkbox a yes/no response." }, "required": { "type": "boolean", "description": "Whether the invitee must answer this booking question." }, "options": { "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 120 }, "minItems": 1, "maxItems": 12, "description": "Choices for a select question; at least one is required when kind=select. Omit for other controls." } }, "required": [ "id", "label", "kind" ], "additionalProperties": false }, "maxItems": 5, "description": "Complete replacement question list. Send [] to remove all questions; omit the field on an update to preserve them." }, "reminder_hours": { "type": "integer", "minimum": 0, "maximum": 336, "description": "Hours before a meeting to send a reminder. Zero disables reminders." }, "collect_phone": { "type": "boolean", "description": "Whether the booking form asks invitees for a phone number." }, "active": { "type": "boolean", "description": "Whether new bookings are accepted. False does not cancel confirmed appointments. Setting true requires the acting member's calendar write permission." } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "bkl_example", "active": false } ] } ``` ```json-schema-response { "type": "object", "properties": { "link": { "description": "The link row plus its public url.", "title": "BookingLink", "type": "object", "properties": { "id": { "type": "string", "description": "Booking link ID. Use it to update or delete this link." }, "org_id": { "type": "string", "description": "Workspace that owns the link." }, "owner_account_id": { "type": "string", "description": "Member whose calendar supplies the available time slots." }, "slug": { "type": "string", "description": "Unique URL segment for this link within the workspace." }, "name": { "type": "string", "description": "Meeting name displayed to invitees." }, "description": { "description": "Introduction displayed on the booking page.", "anyOf": [ { "type": "string", "description": "Introduction displayed on the booking page." }, { "type": "null" } ] }, "duration_minutes": { "type": "integer", "description": "Default meeting length in minutes; the shortest length when several are offered." }, "duration_options": { "description": "Offered meeting lengths in minutes. Null means a fixed duration_minutes.", "anyOf": [ { "type": "array", "items": { "type": "integer" }, "description": "Offered meeting lengths in minutes. Null means a fixed duration_minutes." }, { "type": "null" } ] }, "location_kind": { "type": "string", "enum": [ "video", "phone", "in_person", "custom" ], "description": "video creates a conference link; phone, in_person and custom use location_detail for instructions or an address." }, "location_detail": { "description": "Address, phone instructions or other location details.", "anyOf": [ { "type": "string", "description": "Address, phone instructions or other location details." }, { "type": "null" } ] }, "timezone": { "type": "string", "description": "IANA time zone used to interpret the weekly availability, for example Europe/Oslo." }, "availability": { "type": "object", "properties": { "mon": { "type": "array", "items": { "type": "object", "properties": { "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "Start of the interval." }, "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "End of the interval; must be later than its start." } }, "required": [ "start", "end" ], "additionalProperties": false }, "maxItems": 6, "description": "Monday availability intervals in the booking link's timezone." }, "tue": { "type": "array", "items": { "type": "object", "properties": { "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "Start of the interval." }, "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "End of the interval; must be later than its start." } }, "required": [ "start", "end" ], "additionalProperties": false }, "maxItems": 6, "description": "Tuesday availability intervals in the booking link's timezone." }, "wed": { "type": "array", "items": { "type": "object", "properties": { "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "Start of the interval." }, "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "End of the interval; must be later than its start." } }, "required": [ "start", "end" ], "additionalProperties": false }, "maxItems": 6, "description": "Wednesday availability intervals in the booking link's timezone." }, "thu": { "type": "array", "items": { "type": "object", "properties": { "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "Start of the interval." }, "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "End of the interval; must be later than its start." } }, "required": [ "start", "end" ], "additionalProperties": false }, "maxItems": 6, "description": "Thursday availability intervals in the booking link's timezone." }, "fri": { "type": "array", "items": { "type": "object", "properties": { "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "Start of the interval." }, "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "End of the interval; must be later than its start." } }, "required": [ "start", "end" ], "additionalProperties": false }, "maxItems": 6, "description": "Friday availability intervals in the booking link's timezone." }, "sat": { "type": "array", "items": { "type": "object", "properties": { "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "Start of the interval." }, "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "End of the interval; must be later than its start." } }, "required": [ "start", "end" ], "additionalProperties": false }, "maxItems": 6, "description": "Saturday availability intervals in the booking link's timezone." }, "sun": { "type": "array", "items": { "type": "object", "properties": { "start": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "Start of the interval." }, "end": { "type": "string", "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$", "description": "End of the interval; must be later than its start." } }, "required": [ "start", "end" ], "additionalProperties": false }, "maxItems": 6, "description": "Sunday availability intervals in the booking link's timezone." } }, "additionalProperties": false, "$schema": "http://json-schema.org/draft-07/schema#", "title": "WeeklyAvailability", "description": "Bookable local-time intervals by weekday. Missing or empty days are unavailable." }, "window_days": { "type": "integer", "description": "How many days into the future invitees can book." }, "min_notice_minutes": { "type": "integer", "description": "Minimum time before a meeting can start, in minutes." }, "buffer_before_minutes": { "type": "integer", "description": "Minutes reserved before each meeting." }, "buffer_after_minutes": { "type": "integer", "description": "Minutes reserved after each meeting." }, "max_per_day": { "type": "integer", "description": "Maximum bookings per day. Zero means no daily limit." }, "questions": { "description": "Additional questions shown to invitees. Null means no questions.", "anyOf": [ { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "maxLength": 40, "description": "Stable question key you choose, unique within this link, such as project_goal. Reuse it when editing that question; no create-record call is needed." }, "label": { "type": "string", "minLength": 1, "maxLength": 200, "description": "Text shown for this booking question or choice." }, "kind": { "type": "string", "enum": [ "text", "textarea", "select", "checkbox" ], "description": "Question control: text is a short answer, textarea a longer answer, select a choice from options, and checkbox a yes/no response." }, "required": { "type": "boolean", "description": "Whether the invitee must answer this booking question." }, "options": { "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 120 }, "minItems": 1, "maxItems": 12, "description": "Choices for a select question; at least one is required when kind=select. Omit for other controls." } }, "required": [ "id", "label", "kind" ], "additionalProperties": false }, "maxItems": 5, "$schema": "http://json-schema.org/draft-07/schema#", "description": "Additional questions shown to invitees. Null means no questions." }, { "type": "null" } ] }, "reminder_hours": { "type": "integer", "description": "Hours before the meeting to send a reminder. Zero disables reminders." }, "collect_phone": { "type": "boolean", "description": "Whether invitees are asked for a phone number." }, "active": { "type": "boolean", "description": "Whether invitees can make new bookings through this link." }, "created_at": { "type": "integer", "description": "Creation time in Unix milliseconds." }, "updated_at": { "type": "integer", "description": "Last change in Unix milliseconds." }, "url": { "type": "string", "description": "Public booking URL to share with invitees.", "format": "uri" } }, "required": [ "id", "org_id", "owner_account_id", "slug", "name", "description", "duration_minutes", "duration_options", "location_kind", "location_detail", "timezone", "availability", "window_days", "min_notice_minutes", "buffer_before_minutes", "buffer_after_minutes", "max_per_day", "questions", "reminder_hours", "collect_phone", "active", "created_at", "updated_at", "url" ], "additionalProperties": false } }, "required": [ "link" ], "additionalProperties": false, "examples": [ { "link": { "id": "bkl_example", "org_id": "o_example", "owner_account_id": "a_example", "slug": "project-introduction", "name": "Project introduction", "description": null, "duration_minutes": 30, "duration_options": null, "location_kind": "video", "location_detail": null, "timezone": "Europe/Oslo", "availability": { "mon": [ { "start": "09:00", "end": "17:00" } ] }, "window_days": 30, "min_notice_minutes": 240, "buffer_before_minutes": 0, "buffer_after_minutes": 0, "max_per_day": 0, "questions": null, "reminder_hours": 24, "collect_phone": false, "active": false, "created_at": 1794301200000, "updated_at": 1794301200000, "url": "https://example.com/book/project-introduction" } } ] } ``` --- # Cancel booking Cancel a booking you host, remove its calendar event and notify the invitee. POST https://api.brigg.app/v1/operations/meetings.CancelBooking ## Access & visibility Allow `meetings.CancelBooking` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | Use the booking id from upcoming_bookings, not the link's id from items. [meetings.ListBookingLinks](/developers/reference/meetings/ListBookingLinks). At least 1 character. | | `reason` | string | No | Told to the invitee in the cancellation notice. At most 1000 characters. | ## Booking links and individual bookings A booking link belongs to the acting member and advertises availability in its IANA `timezone`. Availability times are local wall-clock times in that zone; confirmed bookings use numeric timestamps. Use [List booking links](/developers/reference/meetings/ListBookingLinks) to read both links (`items`) and their confirmed bookings starting in the next 366 days (`upcoming_bookings`). The link ID changes or deactivates the booking page. An individual booking ID cancels one confirmed appointment. Deactivating a link stops new bookings without cancelling appointments already made. A link with future bookings cannot be deleted; deactivate it or cancel those bookings first. Active links require a connected writable calendar. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | | 409 | `not_confirmed` | Only confirmed bookings can be cancelled. | ## Next steps - [List booking links](/developers/reference/meetings/ListBookingLinks) - [List calendar connections](/developers/reference/meetings/ListCalendarConnections) - [Update booking link](/developers/reference/meetings/UpdateBookingLink) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.CancelBooking' \ -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_example" }' ``` #### 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.CancelBooking", { 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_example" }), }); 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_example" } request = Request( "https://api.brigg.app/v1/operations/meetings.CancelBooking", 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 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Use the booking id from upcoming_bookings, not the link's id from items. [meetings.ListBookingLinks](/developers/reference/meetings/ListBookingLinks)." }, "reason": { "type": "string", "maxLength": 1000, "description": "Told to the invitee in the cancellation notice." } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." } }, "required": [ "ok" ], "additionalProperties": false, "examples": [ { "ok": true } ] } ``` --- # List calendar connections List your connected calendar accounts and their granted capabilities, calendars and connection status. POST https://api.brigg.app/v1/operations/meetings.ListCalendarConnections ## Access & visibility Allow `meetings.ListCalendarConnections` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/permissions) ## Request No parameters. Send an empty JSON object (`{}`). ## Response Returns **200 OK** with a JSON body. This operation has no continuation cursor. An empty `items` array means no matching visible results were returned. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [Calendar connection](#calendar-connection-response-items) | Yes | Calendar connections available to the acting member, including their calendars and granted capabilities. This operation has no cursor pagination. | ### Calendar connection · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `calendars` | array of [object](#response-items-calendars) | Yes | Individual calendars discovered for this connection, with selection and edit capabilities. | | `can_send_email` | boolean | Yes | Whether this connection has provider permission to send email. The Brigg operation grant is still required. Allowed: `false`, `true`. | | `can_write_calendar` | boolean | Yes | Whether this connection has provider permission to write calendar events. Individual calendars can still be read-only. Allowed: `false`, `true`. | | `can_read_mailbox` | boolean | Yes | Whether this connection has provider permission to read the mailbox. This does not grant the calling API key mailbox access. Allowed: `false`, `true`. | | `id` | string | Yes | Connected calendar account ID. Calendar IDs inside calendars identify individual calendars. | | `provider` | string | Yes | Calendar provider identifier, such as google or microsoft. | | `email` | string | Yes | Email address of the connected provider account. | | `display_name` | null or string | Yes | Provider account's display name, or null when the provider did not supply one. | | `org_id` | string | Yes | Workspace associated with this connection. | | `created_at` | number | Yes | Connection creation time in Unix milliseconds. | | `disabled_at` | null or number | Yes | Time the connection was disabled, in Unix milliseconds; null while not disabled. | | `disabled_reason` | null or string | Yes | Recorded reason for disabling the connection, or null when no reason was recorded. | | `borrowed` | boolean | Yes | Whether this account used the legacy authorization client when it connected. This does not indicate delegation to another member. Allowed: `false`, `true`. | | `scopes` | array of string | Yes | Provider OAuth permissions granted to this connection. These are distinct from Brigg API operation and resource grants. | ### response.items[].calendars[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Unique identifier. Use the value returned by a create or list operation. | | `external_id` | string | Yes | Calendar identifier assigned by the external provider; use the separate Brigg id for Brigg calendar operations. | | `summary` | string | Yes | Calendar's display name in the provider account. | | `primary` | boolean | Yes | Whether the provider marks this as the account's primary calendar. Allowed: `false`, `true`. | | `selected` | boolean | Yes | Whether this calendar is selected for synchronization in Brigg. Allowed: `false`, `true`. | | `color` | null or string | Yes | Calendar display color supplied by the provider, or null when none is supplied. | | `can_edit` | boolean | Yes | Whether the provider permits writes to this individual calendar. The connection's write permission and Brigg grants must also permit the operation. Allowed: `false`, `true`. | | `disabled_at` | null or number | Yes | Time synchronization was disabled, in Unix milliseconds, or null when enabled. | | `synced_through` | string | Yes | Synchronization mode: initial before an incremental cursor is stored, delta afterward. This is not the time of the most recent sync. | | `watch_expires_at` | null or number | Yes | Expiry time of the provider's change-notification subscription in Unix milliseconds, or null when no expiry is recorded. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 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. | ## Next steps [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.ListCalendarConnections' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Brigg-Act-As: $BRIGG_ACT_AS" \ --data-raw '{}' ``` #### 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 response = await fetch("https://api.brigg.app/v1/operations/meetings.ListCalendarConnections", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Brigg-Act-As": actAs, }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/meetings.ListCalendarConnections", 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"], }, 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 { "items": [ { "calendars": [ { "id": "calendar_primary", "external_id": "alex@example.com", "summary": "Alex’s calendar", "primary": true, "selected": true, "color": null, "can_edit": true, "disabled_at": null, "synced_through": "delta", "watch_expires_at": null } ], "can_send_email": false, "can_write_calendar": true, "can_read_mailbox": false, "id": "calendar_account_alex", "provider": "google", "email": "alex@example.com", "display_name": "Alex Morgan", "org_id": "org_example", "created_at": 1794301200000, "disabled_at": null, "disabled_reason": null, "borrowed": false, "scopes": [ "https://www.googleapis.com/auth/calendar.events" ] } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": {}, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "title": "Calendar connection", "type": "object", "properties": { "calendars": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier. Use the value returned by a create or list operation." }, "external_id": { "type": "string", "description": "Calendar identifier assigned by the external provider; use the separate Brigg id for Brigg calendar operations." }, "summary": { "type": "string", "description": "Calendar's display name in the provider account." }, "primary": { "type": "boolean", "enum": [ false, true ], "description": "Whether the provider marks this as the account's primary calendar." }, "selected": { "type": "boolean", "enum": [ false, true ], "description": "Whether this calendar is selected for synchronization in Brigg." }, "color": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Calendar display color supplied by the provider, or null when none is supplied." }, "can_edit": { "type": "boolean", "enum": [ false, true ], "description": "Whether the provider permits writes to this individual calendar. The connection's write permission and Brigg grants must also permit the operation." }, "disabled_at": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Time synchronization was disabled, in Unix milliseconds, or null when enabled." }, "synced_through": { "type": "string", "description": "Synchronization mode: initial before an incremental cursor is stored, delta afterward. This is not the time of the most recent sync." }, "watch_expires_at": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Expiry time of the provider's change-notification subscription in Unix milliseconds, or null when no expiry is recorded." } }, "required": [ "id", "external_id", "summary", "primary", "selected", "color", "can_edit", "disabled_at", "synced_through", "watch_expires_at" ], "additionalProperties": false }, "description": "Individual calendars discovered for this connection, with selection and edit capabilities.", "examples": [ [ { "id": "calendar_primary", "external_id": "alex@example.com", "summary": "Alex’s calendar", "primary": true, "selected": true, "color": null, "can_edit": true, "disabled_at": null, "synced_through": "delta", "watch_expires_at": null } ] ] }, "can_send_email": { "type": "boolean", "enum": [ false, true ], "description": "Whether this connection has provider permission to send email. The Brigg operation grant is still required.", "examples": [ false ] }, "can_write_calendar": { "type": "boolean", "enum": [ false, true ], "description": "Whether this connection has provider permission to write calendar events. Individual calendars can still be read-only.", "examples": [ true ] }, "can_read_mailbox": { "type": "boolean", "enum": [ false, true ], "description": "Whether this connection has provider permission to read the mailbox. This does not grant the calling API key mailbox access.", "examples": [ false ] }, "id": { "type": "string", "description": "Connected calendar account ID. Calendar IDs inside calendars identify individual calendars.", "examples": [ "calendar_account_alex" ] }, "provider": { "type": "string", "description": "Calendar provider identifier, such as google or microsoft.", "examples": [ "google" ] }, "email": { "type": "string", "description": "Email address of the connected provider account.", "examples": [ "alex@example.com" ] }, "display_name": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Provider account's display name, or null when the provider did not supply one.", "examples": [ "Alex Morgan" ] }, "org_id": { "type": "string", "description": "Workspace associated with this connection.", "examples": [ "org_example" ] }, "created_at": { "type": "number", "description": "Connection creation time in Unix milliseconds.", "examples": [ 1794301200000 ] }, "disabled_at": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Time the connection was disabled, in Unix milliseconds; null while not disabled.", "examples": [ null ] }, "disabled_reason": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Recorded reason for disabling the connection, or null when no reason was recorded.", "examples": [ null ] }, "borrowed": { "type": "boolean", "enum": [ false, true ], "description": "Whether this account used the legacy authorization client when it connected. This does not indicate delegation to another member.", "examples": [ false ] }, "scopes": { "type": "array", "items": { "type": "string" }, "description": "Provider OAuth permissions granted to this connection. These are distinct from Brigg API operation and resource grants.", "examples": [ [ "https://www.googleapis.com/auth/calendar.events" ] ] } }, "required": [ "calendars", "can_send_email", "can_write_calendar", "can_read_mailbox", "id", "provider", "email", "display_name", "org_id", "created_at", "disabled_at", "disabled_reason", "borrowed", "scopes" ], "additionalProperties": false }, "description": "Calendar connections available to the acting member, including their calendars and granted capabilities. This operation has no cursor pagination." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "calendars": [ { "id": "calendar_primary", "external_id": "alex@example.com", "summary": "Alex’s calendar", "primary": true, "selected": true, "color": null, "can_edit": true, "disabled_at": null, "synced_through": "delta", "watch_expires_at": null } ], "can_send_email": false, "can_write_calendar": true, "can_read_mailbox": false, "id": "calendar_account_alex", "provider": "google", "email": "alex@example.com", "display_name": "Alex Morgan", "org_id": "org_example", "created_at": 1794301200000, "disabled_at": null, "disabled_reason": null, "borrowed": false, "scopes": [ "https://www.googleapis.com/auth/calendar.events" ] } ] } ] } ``` --- # Select calendar Enable or disable synchronization for one of the caller's connected calendars. Disabling synchronization removes its imported events from Brigg. POST https://api.brigg.app/v1/operations/meetings.SelectCalendar ## Access & visibility Allow `meetings.SelectCalendar` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | Use the Brigg calendar id inside a connection's calendars array, not the connection id or provider externalId. [meetings.ListCalendarConnections](/developers/reference/meetings/ListCalendarConnections). At least 1 character. | | `selected` | boolean | Yes | Whether this calendar is selected for synchronization. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Unique identifier. Use the value returned by a create or list operation. | | `selected` | boolean | Yes | Whether this calendar is selected for synchronization. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | ## Next steps - [List calendar connections](/developers/reference/meetings/ListCalendarConnections) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.SelectCalendar' \ -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_example", "selected": false }' ``` #### 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.SelectCalendar", { 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_example", "selected": false }), }); 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_example", "selected": False } request = Request( "https://api.brigg.app/v1/operations/meetings.SelectCalendar", 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 { "id": "e_example", "selected": false } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Use the Brigg calendar id inside a connection's calendars array, not the connection id or provider externalId. [meetings.ListCalendarConnections](/developers/reference/meetings/ListCalendarConnections)." }, "selected": { "type": "boolean", "description": "Whether this calendar is selected for synchronization." } }, "required": [ "id", "selected" ], "additionalProperties": false, "examples": [ { "id": "e_example", "selected": false } ] } ``` ```json-schema-response { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier. Use the value returned by a create or list operation." }, "selected": { "type": "boolean", "description": "Whether this calendar is selected for synchronization." } }, "required": [ "id", "selected" ], "additionalProperties": false, "examples": [ { "id": "e_example", "selected": false } ] } ``` --- # Get calendar event Read a calendar event by ID. Returns item: null when no visible record matches. POST https://api.brigg.app/v1/operations/meetings.GetCalendarEvent ## Access & visibility Allow `meetings.GetCalendarEvent` on your API key. Resource read permissions: `core:CalendarEvent`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:CalendarEvent` record. Find it with [meetings.ListCalendarEvents](/developers/reference/meetings/ListCalendarEvents). Use the record's top-level `id`, not a business field or account ID. | ## Response Returns **200 OK** with a JSON body. `item: null` means there is no matching record visible to this caller. It does not reveal whether an inaccessible record exists. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. A scheduled calendar event and a recorded meeting have separate IDs and lifecycles. Calendar event operations distinguish Brigg-owned invitations from connected Google or Microsoft events. This list reads stored calendar records visible to the caller, including synchronized connected-calendar events. It does not call Google or Microsoft live, and it is not a free/busy guarantee. A workspace-only key cannot read a member's private synchronized calendar; use approved delegation to that member. Provider synchronization and calendar selection determine which external events have reached Brigg. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [CalendarEventRecord](#calendareventrecord-response-item) or null | Yes | null when no such record | ### CalendarEventRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:CalendarEvent record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [CalendarEvent](#calendarevent-response-item-data) | Yes | The record's fields. | ### CalendarEvent · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string | Yes | Title shown in the calendar invitation. | | `start` | string | Yes | Scheduled start as an ISO 8601 UTC timestamp, for example 2026-10-06T09:00:00.000Z. | | `end` | string | Yes | Scheduled end as an ISO 8601 UTC timestamp; later than start. | | `location` | string | No | Location or meeting link shown in the invitation. | | `description` | string | No | Description included with the scheduled event. | | `agenda` | string | No | Planned discussion topics as text. | | `notes` | string | No | Notes recorded on the calendar event; personal meeting notes are a separate resource. | | `attendees` | array of [CalendarAttendee](#calendarattendee-response-item-data-attendees) | No | Invitation recipients and their responses. Each attendee is identified by email. | | `uid` | string | No | Calendar invitation UID used to correlate updates and cancellations; distinct from the Brigg record ID. | | `sequence` | number | No | Calendar invitation revision number used to order invitation updates. | ### CalendarAttendee · response.item.data.attendees[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `email` | string | Yes | Email address. | | `name` | string | No | Display name. | | `self` | boolean | No | Whether this attendee represents the connected calendar's owner. Allowed: `false`, `true`. | | `response_status` | string | No | Attendee's invitation response: needs_action, accepted, declined or tentative. Allowed: `"needs_action"`, `"accepted"`, `"declined"`, `"tentative"`. | | `optional` | boolean | No | Whether attendance is optional. Allowed: `false`, `true`. | | `resource` | boolean | No | Whether the attendee represents a bookable resource such as a room. Allowed: `false`, `true`. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [List calendar events](/developers/reference/meetings/ListCalendarEvents) - [Delete calendar event](/developers/reference/meetings/DeleteCalendarEvent) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.GetCalendarEvent' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "e_calendarevent_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/meetings.GetCalendarEvent", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "id": "e_calendarevent_example" }), }); 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 payload = { "id": "e_calendarevent_example" } request = Request( "https://api.brigg.app/v1/operations/meetings.GetCalendarEvent", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "item": { "id": "e_calendarevent_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "title": "Northstar project kickoff", "start": "2026-10-06T09:00:00.000Z", "end": "2026-10-06T09:45:00.000Z", "attendees": [ { "email": "alex@example.org", "name": "Alex Morgan", "response_status": "accepted" } ], "uid": "kickoff@example.com", "sequence": 0 } } } ``` ### No visible record A missing or inaccessible record returns item: null. Do not treat this as proof that a record exists for another member. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.GetCalendarEvent' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "e_calendarevent_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/meetings.GetCalendarEvent", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "id": "e_calendarevent_example" }), }); 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 payload = { "id": "e_calendarevent_example" } request = Request( "https://api.brigg.app/v1/operations/meetings.GetCalendarEvent", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "item": null } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:CalendarEvent` record. Find it with [meetings.ListCalendarEvents](/developers/reference/meetings/ListCalendarEvents). Use the record's top-level `id`, not a business field or account ID." } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_calendarevent_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": [ "object", "null" ], "properties": { "id": { "type": "string", "description": "Stable core:CalendarEvent record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "title": { "type": "string", "description": "Title shown in the calendar invitation." }, "start": { "type": "string", "description": "Scheduled start as an ISO 8601 UTC timestamp, for example 2026-10-06T09:00:00.000Z." }, "end": { "type": "string", "description": "Scheduled end as an ISO 8601 UTC timestamp; later than start." }, "location": { "type": "string", "description": "Location or meeting link shown in the invitation." }, "description": { "type": "string", "description": "Description included with the scheduled event." }, "agenda": { "type": "string", "description": "Planned discussion topics as text." }, "notes": { "type": "string", "description": "Notes recorded on the calendar event; personal meeting notes are a separate resource." }, "attendees": { "type": "array", "items": { "title": "CalendarAttendee", "type": "object", "properties": { "email": { "type": "string", "description": "Email address." }, "name": { "type": "string", "description": "Display name." }, "self": { "type": "boolean", "enum": [ false, true ], "description": "Whether this attendee represents the connected calendar's owner." }, "response_status": { "type": "string", "enum": [ "needs_action", "accepted", "declined", "tentative" ], "description": "Attendee's invitation response: needs_action, accepted, declined or tentative." }, "optional": { "type": "boolean", "enum": [ false, true ], "description": "Whether attendance is optional." }, "resource": { "type": "boolean", "enum": [ false, true ], "description": "Whether the attendee represents a bookable resource such as a room." } }, "required": [ "email" ], "additionalProperties": false }, "description": "Invitation recipients and their responses. Each attendee is identified by email." }, "uid": { "type": "string", "description": "Calendar invitation UID used to correlate updates and cancellations; distinct from the Brigg record ID." }, "sequence": { "type": "number", "description": "Calendar invitation revision number used to order invitation updates." } }, "required": [ "title", "start", "end" ], "additionalProperties": false, "description": "The record's fields.", "title": "CalendarEvent" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "null when no such record", "title": "CalendarEventRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_calendarevent_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "title": "Northstar project kickoff", "start": "2026-10-06T09:00:00.000Z", "end": "2026-10-06T09:45:00.000Z", "attendees": [ { "email": "alex@example.org", "name": "Alex Morgan", "response_status": "accepted" } ], "uid": "kickoff@example.com", "sequence": 0 } } } ] } ``` --- # List calendar events List calendar events visible to the credential, with filtering, sorting and cursor pagination. POST https://api.brigg.app/v1/operations/meetings.ListCalendarEvents ## Access & visibility Allow `meetings.ListCalendarEvents` on your API key. Resource read permissions: `core:CalendarEvent`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `filters` | array of [object](#request-filters) | No | Conditions the row must ALL satisfy. | | `sort` | [object](#request-sort) | No | Sort order for the results. Defaults to updated_at descending, with id as a tie-breaker. | | `limit` | integer | No | Maximum number of results to return in this page. Continue with next_cursor when returned. Default: `100`. Minimum: 1. | | `cursor` | string | No | The `next_cursor` of the previous page. | ### request.filters[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | `data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private. Allowed: `"id"`, `"created_at"`, `"updated_at"`, `"created_by"`, `"private"`, `"data.title"`, `"data.start"`, `"data.end"`, `"data.location"`, `"data.description"`, `"data.agenda"`, `"data.notes"`, `"data.attendees"`, `"data.uid"`, `"data.sequence"`. | | `op` | string | Yes | Comparison operator. Use in with an array, or omit value for is_empty and is_not_empty. Allowed: `"eq"`, `"neq"`, `"contains"`, `"starts_with"`, `"gt"`, `"gte"`, `"lt"`, `"lte"`, `"in"`, `"has"`, `"is_empty"`, `"is_not_empty"`. | | `value` | JSON value | No | The comparison value; an array for `in`; omitted for is_empty / is_not_empty. | ### request.sort | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | `data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private. Allowed: `"id"`, `"created_at"`, `"updated_at"`, `"created_by"`, `"private"`, `"data.title"`, `"data.start"`, `"data.end"`, `"data.location"`, `"data.description"`, `"data.agenda"`, `"data.notes"`, `"data.attendees"`, `"data.uid"`, `"data.sequence"`. | | `direction` | string | No | Sort direction: asc for ascending or desc for descending. Allowed: `"asc"`, `"desc"`. | ## Filtering and sorting All conditions are combined with **AND**. Address business fields as `data.`, and record metadata as `id`, `created_at`, `updated_at`, `created_by` or `private`. A field path names one field; it does not traverse nested objects. | Operator | Meaning | Value | | --- | --- | --- | | `eq` | Equal to a scalar | String, number, boolean or null | | `neq` | Not equal; missing values also match | String, number, boolean or null | | `contains` | Case-insensitive text contains | String; % and _ are literal characters | | `starts_with` | Case-insensitive text prefix | String | | `gt`, `gte` | Greater than / at least | Number or string appropriate to the field | | `lt`, `lte` | Less than / at most | Number or string appropriate to the field | | `in` | Equal to any supplied scalar | Nonempty array of strings, numbers, booleans or null | | `has` | Array contains a string | One string; does not match properties inside array objects | | `is_empty` | Missing, null, empty string or empty array | Omit value | | `is_not_empty` | Has a nonempty value | Omit value | Match the stored field's type. Numeric business timestamps take Unix milliseconds; date-only business fields take `YYYY-MM-DD`. The record metadata fields `created_at` and `updated_at` also accept ISO timestamps for ordered comparisons. Sorting defaults to `updated_at` descending. If you supply `sort.field` without `sort.direction`, direction is `desc`. The record ID breaks ties; missing values sort last. ## Response Returns **200 OK** with a JSON body. An empty `items` array means this page contains no matching visible results. Follow `next_cursor` when present. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. A scheduled calendar event and a recorded meeting have separate IDs and lifecycles. Calendar event operations distinguish Brigg-owned invitations from connected Google or Microsoft events. This list reads stored calendar records visible to the caller, including synchronized connected-calendar events. It does not call Google or Microsoft live, and it is not a free/busy guarantee. A workspace-only key cannot read a member's private synchronized calendar; use approved delegation to that member. Provider synchronization and calendar selection determine which external events have reached Brigg. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [CalendarEventRecord](#calendareventrecord-response-items) | Yes | Records visible under the credential's grants and the selected data scope, matching the requested filters. Pass next_cursor as cursor to continue when a next cursor is returned. | | `next_cursor` | string | No | Pass this value as cursor to continue with the same filters, sort and credential. Omitted when there are no more results. | ### CalendarEventRecord · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:CalendarEvent record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [CalendarEvent](#calendarevent-response-items-data) | Yes | The record's fields. | ### CalendarEvent · response.items[].data | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string | Yes | Title shown in the calendar invitation. | | `start` | string | Yes | Scheduled start as an ISO 8601 UTC timestamp, for example 2026-10-06T09:00:00.000Z. | | `end` | string | Yes | Scheduled end as an ISO 8601 UTC timestamp; later than start. | | `location` | string | No | Location or meeting link shown in the invitation. | | `description` | string | No | Description included with the scheduled event. | | `agenda` | string | No | Planned discussion topics as text. | | `notes` | string | No | Notes recorded on the calendar event; personal meeting notes are a separate resource. | | `attendees` | array of [CalendarAttendee](#calendarattendee-response-items-data-attendees) | No | Invitation recipients and their responses. Each attendee is identified by email. | | `uid` | string | No | Calendar invitation UID used to correlate updates and cancellations; distinct from the Brigg record ID. | | `sequence` | number | No | Calendar invitation revision number used to order invitation updates. | ### CalendarAttendee · response.items[].data.attendees[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `email` | string | Yes | Email address. | | `name` | string | No | Display name. | | `self` | boolean | No | Whether this attendee represents the connected calendar's owner. Allowed: `false`, `true`. | | `response_status` | string | No | Attendee's invitation response: needs_action, accepted, declined or tentative. Allowed: `"needs_action"`, `"accepted"`, `"declined"`, `"tentative"`. | | `optional` | boolean | No | Whether attendance is optional. Allowed: `false`, `true`. | | `resource` | boolean | No | Whether the attendee represents a bookable resource such as a room. Allowed: `false`, `true`. | ## Pagination Pass `next_cursor` from the response as `cursor` on the next request. Keep the same filters, sort and acting identity. Stop when `next_cursor` is absent; do not infer completion from the number of items. The default page size is **100**; `limit` must be a positive integer. **Pagination is a live view, not a snapshot.** Changes between pages can move records across page boundaries. Upsert by record ID rather than appending blindly. For recurring synchronization, use an overlapping update window and deduplicate records. Periodically reconcile IDs to detect deletions. [Resource webhooks](/developers/webhooks) can supplement synchronization for eligible workspace-shared records only: they do not export private or project-scoped records. Personal data still needs polling and reconciliation. ```typescript const query = { "limit": 10 }; let cursor; do { const response = await fetch("https://api.brigg.app/v1/operations/meetings.ListCalendarEvents", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ ...query, ...(cursor ? { cursor } : {}) }), }); const page = await response.json(); if (!response.ok) throw new Error(`${response.status}: ${page.message}`); for (const item of page.items) { console.log(item); // Process or upsert each result. } cursor = page.next_cursor; } while (cursor); ``` ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | | 400 | `cursor_invalid` | Restart pagination with no cursor. | | 400 | `cursor_mismatch` | Use the cursor with the original filters, sort order and credential. | ## Next steps - [Get calendar event](/developers/reference/meetings/GetCalendarEvent) - [Delete calendar event](/developers/reference/meetings/DeleteCalendarEvent) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### First page Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.ListCalendarEvents' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "limit": 10 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/meetings.ListCalendarEvents", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "limit": 10 }), }); 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 payload = { "limit": 10 } request = Request( "https://api.brigg.app/v1/operations/meetings.ListCalendarEvents", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_calendarevent_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "title": "Northstar project kickoff", "start": "2026-10-06T09:00:00.000Z", "end": "2026-10-06T09:45:00.000Z", "attendees": [ { "email": "alex@example.org", "name": "Alex Morgan", "response_status": "accepted" } ], "uid": "kickoff@example.com", "sequence": 0 } } ] } ``` ### Events overlapping a time window 6 October 2026, 08:00–17:00 UTC. start < window end AND end > window start includes events that began before the window. ISO timestamps are distinct from numeric Meeting timestamps. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.ListCalendarEvents' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "limit": 50, "filters": [ { "field": "data.start", "op": "lt", "value": "2026-10-06T17:00:00.000Z" }, { "field": "data.end", "op": "gt", "value": "2026-10-06T08:00:00.000Z" } ], "sort": { "field": "data.start", "direction": "asc" } }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/meetings.ListCalendarEvents", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "limit": 50, "filters": [ { "field": "data.start", "op": "lt", "value": "2026-10-06T17:00:00.000Z" }, { "field": "data.end", "op": "gt", "value": "2026-10-06T08:00:00.000Z" } ], "sort": { "field": "data.start", "direction": "asc" } }), }); 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 payload = { "limit": 50, "filters": [ { "field": "data.start", "op": "lt", "value": "2026-10-06T17:00:00.000Z" }, { "field": "data.end", "op": "gt", "value": "2026-10-06T08:00:00.000Z" } ], "sort": { "field": "data.start", "direction": "asc" } } request = Request( "https://api.brigg.app/v1/operations/meetings.ListCalendarEvents", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_calendarevent_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "title": "Northstar project kickoff", "start": "2026-10-06T09:00:00.000Z", "end": "2026-10-06T09:45:00.000Z", "attendees": [ { "email": "alex@example.org", "name": "Alex Morgan", "response_status": "accepted" } ], "uid": "kickoff@example.com", "sequence": 0 } } ] } ``` ### Records updated since a checkpoint 6 October 2026 at 00:00 UTC. Use an overlap window and upsert by ID when synchronizing. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.ListCalendarEvents' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/meetings.ListCalendarEvents", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 }), }); 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 payload = { "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 } request = Request( "https://api.brigg.app/v1/operations/meetings.ListCalendarEvents", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_calendarevent_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "title": "Northstar project kickoff", "start": "2026-10-06T09:00:00.000Z", "end": "2026-10-06T09:45:00.000Z", "attendees": [ { "email": "alex@example.org", "name": "Alex Morgan", "response_status": "accepted" } ], "uid": "kickoff@example.com", "sequence": 0 } } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "filters": { "type": "array", "items": { "type": "object", "properties": { "field": { "type": "string", "description": "`data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private.", "enum": [ "id", "created_at", "updated_at", "created_by", "private", "data.title", "data.start", "data.end", "data.location", "data.description", "data.agenda", "data.notes", "data.attendees", "data.uid", "data.sequence" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "contains", "starts_with", "gt", "gte", "lt", "lte", "in", "has", "is_empty", "is_not_empty" ], "description": "Comparison operator. Use in with an array, or omit value for is_empty and is_not_empty." }, "value": { "description": "The comparison value; an array for `in`; omitted for is_empty / is_not_empty." } }, "required": [ "field", "op" ], "additionalProperties": false }, "description": "Conditions the row must ALL satisfy." }, "sort": { "type": "object", "properties": { "field": { "type": "string", "description": "`data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private.", "enum": [ "id", "created_at", "updated_at", "created_by", "private", "data.title", "data.start", "data.end", "data.location", "data.description", "data.agenda", "data.notes", "data.attendees", "data.uid", "data.sequence" ] }, "direction": { "type": "string", "enum": [ "asc", "desc" ], "description": "Sort direction: asc for ascending or desc for descending." } }, "required": [ "field" ], "additionalProperties": false, "description": "Sort order for the results. Defaults to updated_at descending, with id as a tie-breaker." }, "limit": { "type": "integer", "minimum": 1, "default": 100, "description": "Maximum number of results to return in this page. Continue with next_cursor when returned." }, "cursor": { "type": "string", "description": "The `next_cursor` of the previous page." } }, "additionalProperties": false, "examples": [ { "limit": 10 } ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:CalendarEvent record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "title": { "type": "string", "description": "Title shown in the calendar invitation." }, "start": { "type": "string", "description": "Scheduled start as an ISO 8601 UTC timestamp, for example 2026-10-06T09:00:00.000Z." }, "end": { "type": "string", "description": "Scheduled end as an ISO 8601 UTC timestamp; later than start." }, "location": { "type": "string", "description": "Location or meeting link shown in the invitation." }, "description": { "type": "string", "description": "Description included with the scheduled event." }, "agenda": { "type": "string", "description": "Planned discussion topics as text." }, "notes": { "type": "string", "description": "Notes recorded on the calendar event; personal meeting notes are a separate resource." }, "attendees": { "type": "array", "items": { "title": "CalendarAttendee", "type": "object", "properties": { "email": { "type": "string", "description": "Email address." }, "name": { "type": "string", "description": "Display name." }, "self": { "type": "boolean", "enum": [ false, true ], "description": "Whether this attendee represents the connected calendar's owner." }, "response_status": { "type": "string", "enum": [ "needs_action", "accepted", "declined", "tentative" ], "description": "Attendee's invitation response: needs_action, accepted, declined or tentative." }, "optional": { "type": "boolean", "enum": [ false, true ], "description": "Whether attendance is optional." }, "resource": { "type": "boolean", "enum": [ false, true ], "description": "Whether the attendee represents a bookable resource such as a room." } }, "required": [ "email" ], "additionalProperties": false }, "description": "Invitation recipients and their responses. Each attendee is identified by email." }, "uid": { "type": "string", "description": "Calendar invitation UID used to correlate updates and cancellations; distinct from the Brigg record ID." }, "sequence": { "type": "number", "description": "Calendar invitation revision number used to order invitation updates." } }, "required": [ "title", "start", "end" ], "additionalProperties": false, "description": "The record's fields.", "title": "CalendarEvent" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "title": "CalendarEventRecord" }, "description": "Records visible under the credential's grants and the selected data scope, matching the requested filters. Pass next_cursor as cursor to continue when a next cursor is returned." }, "next_cursor": { "type": "string", "description": "Pass this value as cursor to continue with the same filters, sort and credential. Omitted when there are no more results." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "id": "e_calendarevent_example", "created_at": 1791276900000, "updated_at": 1791280800000, "created_by": "a_jamie", "private": false, "data": { "title": "Northstar project kickoff", "start": "2026-10-06T09:00:00.000Z", "end": "2026-10-06T09:45:00.000Z", "attendees": [ { "email": "alex@example.org", "name": "Alex Morgan", "response_status": "accepted" } ], "uid": "kickoff@example.com", "sequence": 0 } } ] } ] } ``` --- # Cancel calendar event Delete a Brigg-owned calendar event and optionally send cancellation notices to attendees. Set send_cancel to send those notices. This does not cancel an event in a connected Google or Microsoft calendar. POST https://api.brigg.app/v1/operations/meetings.CancelCalendarEvent ## Access & visibility Allow `meetings.CancelCalendarEvent` on your API key. Resource write permissions: `core:CalendarEvent`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | The core:CalendarEvent entry id. At least 1 character. | | `send_cancel` | boolean | No | Mail an iCal CANCEL to every attendee. | | `message` | string | No | Message included with the calendar invitation update or cancellation. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Unique identifier. Use the value returned by a create or list operation. | | `uid` | string | Yes | Calendar invitation UID, distinct from the Brigg record ID. | | `send` | [object](#response-send) | No | Present when a mail-out was asked for. | ### response.send | Field | Type | Required | Description | | --- | --- | --- | --- | | `message_ids` | map of string | Yes | Recipient email address to delivery message ID. | | `skipped` | array of string | Yes | Attendee account ids with no email address. | | `rate_limited` | boolean | No | The org's invite quota was hit — the event write landed, no mail went out. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.CancelCalendarEvent' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_example" }' ``` #### TypeScript ```typescript 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.CancelCalendarEvent", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_example" }), }); 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_example" } request = Request( "https://api.brigg.app/v1/operations/meetings.CancelCalendarEvent", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "id": "e_example", "uid": "kickoff@example.com" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "The core:CalendarEvent entry id." }, "send_cancel": { "type": "boolean", "description": "Mail an iCal CANCEL to every attendee." }, "message": { "type": "string", "description": "Message included with the calendar invitation update or cancellation." } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier. Use the value returned by a create or list operation." }, "uid": { "type": "string", "description": "Calendar invitation UID, distinct from the Brigg record ID." }, "send": { "type": "object", "description": "Present when a mail-out was asked for.", "properties": { "message_ids": { "description": "Recipient email address to delivery message ID.", "type": "object", "additionalProperties": { "type": "string" } }, "skipped": { "type": "array", "items": { "type": "string" }, "description": "Attendee account ids with no email address." }, "rate_limited": { "type": "boolean", "description": "The org's invite quota was hit — the event write landed, no mail went out." } }, "required": [ "message_ids", "skipped" ], "additionalProperties": false } }, "required": [ "id", "uid" ], "additionalProperties": false, "examples": [ { "id": "e_example", "uid": "kickoff@example.com" } ] } ``` --- # Create calendar event Create a Brigg-owned calendar event and optionally send email invitations. This does not create an event inside a person’s connected Google or Microsoft calendar. POST https://api.brigg.app/v1/operations/meetings.CreateCalendarEvent ## Access & visibility Allow `meetings.CreateCalendarEvent` on your API key. Resource write permissions: `core:CalendarEvent`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `title` | string | Yes | Display title. At least 1 character. | | `start` | string | Yes | Start timestamp with an explicit time zone, for example 2026-11-10T10:00:00+01:00. Brigg normalizes it to UTC. Do not send a date without a time zone. | | `end` | string | Yes | End timestamp with an explicit time zone, strictly later than start. Returned calendar times use UTC. | | `location` | string | No | Physical address or meeting location supplied to invitees. | | `description` | string | No | Descriptive text. | | `agenda` | string | No | Discussion topics planned for the meeting. | | `notes` | string | No | Notes supplied for the calendar event. | | `attendees` | array of string | No | Workspace member account IDs from [List colleagues](/developers/reference/workspace/ListColleagues), not Person record IDs or email addresses. Members without an email address are returned in send.skipped. | | `visibility` | array of string | No | Reserved compatibility field; it currently has no effect. Omit it. It cannot make the calendar event private or grant access to attendees. At least 1 item. | | `send_invite` | boolean | No | Send email invitations after saving the event. Defaults to false. Requires at least one attendee with an email address. | | `message` | string | No | The cover note of the mail, instead of the default. | ## Choose the calendar you mean This creates a Brigg-owned calendar record. Use [Create connected calendar event](/developers/reference/meetings/CreateConnectedCalendarEvent) to write to Google or Microsoft instead. Use [Create meeting](/developers/reference/meetings/CreateMeeting) for a meeting record with notes and summaries. These are different resources. Omit `send_invite` or set it to false to save without email. To send invitations, find member account IDs with [List colleagues](/developers/reference/workspace/ListColleagues) and set `send_invite: true`. Email addresses and customer Person IDs are not accepted as attendee identities by this operation. ## Handle invitation delivery separately The calendar event is saved before invitations are attempted. `send.message_ids` lists submitted emails, not proof of delivery. `send.skipped` contains member IDs without usable email addresses. If `send.rate_limited` is true, the event exists but invitations were not sent. Do not create the event again. After resolving delivery or quota issues, use [Update calendar event](/developers/reference/meetings/UpdateCalendarEvent) with the returned `id`, `send_update: true` and a new idempotency key. Retrying the original create with its original key returns that create's recorded outcome; it does not constitute a new send attempt. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Brigg calendar record ID. Use it with [Get calendar event](/developers/reference/meetings/GetCalendarEvent) or [Update calendar event](/developers/reference/meetings/UpdateCalendarEvent). | | `uid` | string | Yes | Calendar invitation UID, distinct from the Brigg record ID. | | `sequence` | number | Yes | Calendar invitation revision number. | | `send` | [object](#response-send) | No | Invitation attempt result. Absent when no invitation attempt was made; the saved event exists independently of this result. | ### response.send | Field | Type | Required | Description | | --- | --- | --- | --- | | `message_ids` | map of string | Yes | Recipient email address to delivery message ID. | | `skipped` | array of string | Yes | Attendee account ids with no email address. | | `rate_limited` | boolean | No | The org's invite quota was hit — the event write landed, no mail went out. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [Get calendar event](/developers/reference/meetings/GetCalendarEvent) - [Update calendar event](/developers/reference/meetings/UpdateCalendarEvent) - [Create connected calendar event](/developers/reference/meetings/CreateConnectedCalendarEvent) - [List colleagues](/developers/reference/workspace/ListColleagues) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Save without sending Times are UTC. No invitations are sent when send_invite is omitted. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.CreateCalendarEvent' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "title": "Northstar project kickoff", "start": "2026-11-10T09:00:00.000Z", "end": "2026-11-10T09:45:00.000Z" }' ``` #### TypeScript ```typescript 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.CreateCalendarEvent", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "title": "Northstar project kickoff", "start": "2026-11-10T09:00:00.000Z", "end": "2026-11-10T09:45:00.000Z" }), }); 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 = { "title": "Northstar project kickoff", "start": "2026-11-10T09:00:00.000Z", "end": "2026-11-10T09:45:00.000Z" } request = Request( "https://api.brigg.app/v1/operations/meetings.CreateCalendarEvent", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "id": "e_calendar_kickoff", "uid": "kickoff@example.com", "sequence": 0 } ``` ### Invite workspace members Use real account IDs from List colleagues. The response maps submitted emails to message IDs. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.CreateCalendarEvent' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "title": "Northstar project kickoff", "start": "2026-11-10T09:00:00.000Z", "end": "2026-11-10T09:45:00.000Z", "attendees": [ "a_jamie" ], "send_invite": true, "message": "Please join the project kickoff." }' ``` #### TypeScript ```typescript 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.CreateCalendarEvent", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "title": "Northstar project kickoff", "start": "2026-11-10T09:00:00.000Z", "end": "2026-11-10T09:45:00.000Z", "attendees": [ "a_jamie" ], "send_invite": true, "message": "Please join the project 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 = { "title": "Northstar project kickoff", "start": "2026-11-10T09:00:00.000Z", "end": "2026-11-10T09:45:00.000Z", "attendees": [ "a_jamie" ], "send_invite": True, "message": "Please join the project kickoff." } request = Request( "https://api.brigg.app/v1/operations/meetings.CreateCalendarEvent", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "id": "e_calendar_kickoff", "uid": "kickoff@example.com", "sequence": 0, "send": { "message_ids": { "jamie@example.com": "msg_kickoff" }, "skipped": [], "rate_limited": false } } ``` ### Event saved, invitations held Handle this successful HTTP response as partial completion. Keep the event ID and retry delivery separately. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.CreateCalendarEvent' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "title": "Northstar project kickoff", "start": "2026-11-10T09:00:00.000Z", "end": "2026-11-10T09:45:00.000Z", "attendees": [ "a_jamie" ], "send_invite": true }' ``` #### TypeScript ```typescript 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.CreateCalendarEvent", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "title": "Northstar project kickoff", "start": "2026-11-10T09:00:00.000Z", "end": "2026-11-10T09:45:00.000Z", "attendees": [ "a_jamie" ], "send_invite": true }), }); 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 = { "title": "Northstar project kickoff", "start": "2026-11-10T09:00:00.000Z", "end": "2026-11-10T09:45:00.000Z", "attendees": [ "a_jamie" ], "send_invite": True } request = Request( "https://api.brigg.app/v1/operations/meetings.CreateCalendarEvent", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "id": "e_calendar_kickoff", "uid": "kickoff@example.com", "sequence": 0, "send": { "message_ids": {}, "skipped": [], "rate_limited": true } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "title": { "type": "string", "minLength": 1, "description": "Display title." }, "start": { "type": "string", "description": "Start timestamp with an explicit time zone, for example 2026-11-10T10:00:00+01:00. Brigg normalizes it to UTC. Do not send a date without a time zone." }, "end": { "type": "string", "description": "End timestamp with an explicit time zone, strictly later than start. Returned calendar times use UTC." }, "location": { "type": "string", "description": "Physical address or meeting location supplied to invitees." }, "description": { "type": "string", "description": "Descriptive text." }, "agenda": { "type": "string", "description": "Discussion topics planned for the meeting." }, "notes": { "type": "string", "description": "Notes supplied for the calendar event." }, "attendees": { "type": "array", "items": { "type": "string" }, "description": "Workspace member account IDs from [List colleagues](/developers/reference/workspace/ListColleagues), not Person record IDs or email addresses. Members without an email address are returned in send.skipped." }, "visibility": { "type": "array", "items": { "type": "string" }, "minItems": 1, "description": "Reserved compatibility field; it currently has no effect. Omit it. It cannot make the calendar event private or grant access to attendees." }, "send_invite": { "type": "boolean", "description": "Send email invitations after saving the event. Defaults to false. Requires at least one attendee with an email address." }, "message": { "type": "string", "description": "The cover note of the mail, instead of the default." } }, "required": [ "title", "start", "end" ], "additionalProperties": false, "examples": [ { "title": "Northstar project kickoff", "start": "2026-11-10T09:00:00.000Z", "end": "2026-11-10T09:45:00.000Z" } ] } ``` ```json-schema-response { "type": "object", "properties": { "id": { "type": "string", "description": "Brigg calendar record ID. Use it with [Get calendar event](/developers/reference/meetings/GetCalendarEvent) or [Update calendar event](/developers/reference/meetings/UpdateCalendarEvent)." }, "uid": { "type": "string", "description": "Calendar invitation UID, distinct from the Brigg record ID." }, "sequence": { "type": "number", "description": "Calendar invitation revision number." }, "send": { "type": "object", "description": "Invitation attempt result. Absent when no invitation attempt was made; the saved event exists independently of this result.", "properties": { "message_ids": { "description": "Recipient email address to delivery message ID.", "type": "object", "additionalProperties": { "type": "string" } }, "skipped": { "type": "array", "items": { "type": "string" }, "description": "Attendee account ids with no email address." }, "rate_limited": { "type": "boolean", "description": "The org's invite quota was hit — the event write landed, no mail went out." } }, "required": [ "message_ids", "skipped" ], "additionalProperties": false } }, "required": [ "id", "uid", "sequence" ], "additionalProperties": false, "examples": [ { "id": "e_calendar_kickoff", "uid": "kickoff@example.com", "sequence": 0 } ] } ``` --- # Delete calendar event Delete the Brigg calendar record. Use CancelCalendarEvent when attendees need a cancellation notice. Connected-provider events have a separate personal calendar workflow. POST https://api.brigg.app/v1/operations/meetings.DeleteCalendarEvent ## Access & visibility Allow `meetings.DeleteCalendarEvent` on your API key. Resource read permissions: `core:CalendarEvent`. Resource write permissions: `core:CalendarEvent`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:CalendarEvent` record. Find it with [meetings.ListCalendarEvents](/developers/reference/meetings/ListCalendarEvents). Use the record's top-level `id`, not a business field or account ID. | | `expected` | [object](#request-expected) | No | Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {"$absent":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource. | ### request.expected | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string or [object](#request-expected-title) | No | Commit only if the previous title value matches; use $absent to require that this field is missing. | | `start` | string or [object](#request-expected-start) | No | Commit only if the previous start value matches; use $absent to require that this field is missing. | | `end` | string or [object](#request-expected-end) | No | Commit only if the previous end value matches; use $absent to require that this field is missing. | | `location` | string or [object](#request-expected-location) | No | Commit only if the previous location value matches; use $absent to require that this field is missing. | | `description` | string or [object](#request-expected-description) | No | Commit only if the previous description value matches; use $absent to require that this field is missing. | | `agenda` | string or [object](#request-expected-agenda) | No | Commit only if the previous agenda value matches; use $absent to require that this field is missing. | | `notes` | string or [object](#request-expected-notes) | No | Commit only if the previous notes value matches; use $absent to require that this field is missing. | | `attendees` | array of [CalendarAttendee](#calendarattendee-request-expected-attendees) or [object](#request-expected-attendees) | No | Commit only if the previous attendees value matches; use $absent to require that this field is missing. | | `uid` | string or [object](#request-expected-uid) | No | Commit only if the previous uid value matches; use $absent to require that this field is missing. | | `sequence` | number or [object](#request-expected-sequence) | No | Commit only if the previous sequence value matches; use $absent to require that this field is missing. | ### request.expected.title | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.start | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.end | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.location | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.description | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.agenda | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.notes | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.attendees | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### CalendarAttendee · request.expected.attendees[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `email` | string | Yes | Email address. | | `name` | string | No | Display name. | | `self` | boolean | No | Whether this attendee represents the connected calendar's owner. Allowed: `false`, `true`. | | `response_status` | string | No | Attendee's invitation response: needs_action, accepted, declined or tentative. Allowed: `"needs_action"`, `"accepted"`, `"declined"`, `"tentative"`. | | `optional` | boolean | No | Whether attendance is optional. Allowed: `false`, `true`. | | `resource` | boolean | No | Whether the attendee represents a bookable resource such as a room. Allowed: `false`, `true`. | ### request.expected.uid | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.sequence | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ## Deletion and retries A successful response reports whether this call removed the record or it was already absent. Check `cascaded` for dependent record IDs returned by the operation. Retrying the same action uses the original idempotency key. A successful deletion is not an archive you can restore through this operation. To avoid deleting a record someone has changed, read it first and put the relevant prior business values in `expected`. Keys are relative to `data`, not prefixed with `data.`. Use {"$absent": true} to require a missing field. A mismatch returns 409 conflict; read again and decide whether deletion is still appropriate. A revised action needs a new idempotency key. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `deleted` | string | Yes | deleted when this request removed the record; already_deleted when it was already absent. Allowed: `"deleted"`, `"already_deleted"`. | | `cascaded` | array of string | No | IDs of dependent records deleted with this 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `conflict` | A supplied expected value no longer matches. Read the record again before deciding whether to retry. | ## Next steps - [List calendar events](/developers/reference/meetings/ListCalendarEvents) - [Get calendar event](/developers/reference/meetings/GetCalendarEvent) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.DeleteCalendarEvent' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_calendarevent_example" }' ``` #### TypeScript ```typescript 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.DeleteCalendarEvent", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_calendarevent_example" }), }); 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_calendarevent_example" } request = Request( "https://api.brigg.app/v1/operations/meetings.DeleteCalendarEvent", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "deleted": "deleted" } ``` ### Delete only if unchanged Use a value you actually read. A concurrent change refuses the write with 409 conflict. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.DeleteCalendarEvent' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_calendarevent_example", "expected": { "title": "Northstar project kickoff" } }' ``` #### TypeScript ```typescript 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.DeleteCalendarEvent", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_calendarevent_example", "expected": { "title": "Northstar project 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_calendarevent_example", "expected": { "title": "Northstar project kickoff" } } request = Request( "https://api.brigg.app/v1/operations/meetings.DeleteCalendarEvent", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "deleted": "deleted" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:CalendarEvent` record. Find it with [meetings.ListCalendarEvents](/developers/reference/meetings/ListCalendarEvents). Use the record's top-level `id`, not a business field or account ID." }, "expected": { "type": "object", "description": "Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {\"$absent\":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource.", "additionalProperties": false, "properties": { "title": { "description": "Commit only if the previous title value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Title shown in the calendar invitation." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "start": { "description": "Commit only if the previous start value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Scheduled start as an ISO 8601 UTC timestamp, for example 2026-10-06T09:00:00.000Z." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "end": { "description": "Commit only if the previous end value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Scheduled end as an ISO 8601 UTC timestamp; later than start." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "location": { "description": "Commit only if the previous location value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Location or meeting link shown in the invitation." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "description": { "description": "Commit only if the previous description value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Description included with the scheduled event." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "agenda": { "description": "Commit only if the previous agenda value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Planned discussion topics as text." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "notes": { "description": "Commit only if the previous notes value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Notes recorded on the calendar event; personal meeting notes are a separate resource." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "attendees": { "description": "Commit only if the previous attendees value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "array", "items": { "title": "CalendarAttendee", "type": "object", "properties": { "email": { "type": "string", "description": "Email address." }, "name": { "type": "string", "description": "Display name." }, "self": { "type": "boolean", "enum": [ false, true ], "description": "Whether this attendee represents the connected calendar's owner." }, "response_status": { "type": "string", "enum": [ "needs_action", "accepted", "declined", "tentative" ], "description": "Attendee's invitation response: needs_action, accepted, declined or tentative." }, "optional": { "type": "boolean", "enum": [ false, true ], "description": "Whether attendance is optional." }, "resource": { "type": "boolean", "enum": [ false, true ], "description": "Whether the attendee represents a bookable resource such as a room." } }, "required": [ "email" ], "additionalProperties": false }, "description": "Invitation recipients and their responses. Each attendee is identified by email." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "uid": { "description": "Commit only if the previous uid value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Calendar invitation UID used to correlate updates and cancellations; distinct from the Brigg record ID." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "sequence": { "description": "Commit only if the previous sequence value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "number", "description": "Calendar invitation revision number used to order invitation updates." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] } } } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_calendarevent_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "deleted": { "type": "string", "enum": [ "deleted", "already_deleted" ], "description": "deleted when this request removed the record; already_deleted when it was already absent." }, "cascaded": { "type": "array", "items": { "type": "string" }, "description": "IDs of dependent records deleted with this record." } }, "required": [ "deleted" ], "additionalProperties": false, "examples": [ { "deleted": "deleted" } ] } ``` --- # Update calendar event Update a Brigg-owned calendar event. Set send_update to send updated invitations to attendees. This does not change an event in a connected Google or Microsoft calendar. POST https://api.brigg.app/v1/operations/meetings.UpdateCalendarEvent ## Access & visibility Allow `meetings.UpdateCalendarEvent` on your API key. Resource write permissions: `core:CalendarEvent`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | The core:CalendarEvent entry id. At least 1 character. | | `patch` | [object](#request-patch) | Yes | Requested changes to the calendar event. | | `send_update` | boolean | No | Mail the updated invitation to every attendee. | | `message` | string | No | Message included with the calendar invitation update or cancellation. | ### request.patch | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string | No | Display title. At least 1 character. | | `start` | string | No | Start timestamp with an explicit time zone, for example 2026-11-10T10:00:00+01:00. Brigg normalizes it to UTC. Do not send a date without a time zone. | | `end` | string | No | End timestamp with an explicit time zone, strictly later than start. Returned calendar times use UTC. | | `location` | string | No | Physical address or meeting location supplied to invitees. | | `description` | string | No | Descriptive text. | | `agenda` | string | No | Discussion topics planned for the meeting. | | `notes` | string | No | Notes supplied for the calendar event. | | `attendees` | array of string | No | Workspace member account IDs from [List colleagues](/developers/reference/workspace/ListColleagues), not Person record IDs or email addresses. Members without an email address are returned in send.skipped. | | `visibility` | array of string | No | Reserved compatibility field; it currently has no effect. Omit it. It cannot make the calendar event private or grant access to attendees. At least 1 item. | ## Update the saved event and its invitations Use the Brigg event `id` from [List calendar events](/developers/reference/meetings/ListCalendarEvents). Send only changed fields in `patch`. `send_update` defaults to false. Set it to true to email the event's attendees. The response's `significant` flag indicates an invitation-relevant change; `sequence` advances for such changes. The event update can succeed even when email is held: inspect `send.rate_limited` and `send.skipped`. A new delivery attempt is a new action with a new idempotency key. Retrying a lost response to the same action reuses its original key. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Unique identifier. Use the value returned by a create or list operation. | | `uid` | string | Yes | Calendar invitation UID, distinct from the Brigg record ID. | | `sequence` | number | Yes | Calendar invitation revision number. | | `significant` | boolean | Yes | Whether time or place changed. | | `send` | [object](#response-send) | No | Present when a mail-out was asked for. | ### response.send | Field | Type | Required | Description | | --- | --- | --- | --- | | `message_ids` | map of string | Yes | Recipient email address to delivery message ID. | | `skipped` | array of string | Yes | Attendee account ids with no email address. | | `rate_limited` | boolean | No | The org's invite quota was hit — the event write landed, no mail went out. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [Get calendar event](/developers/reference/meetings/GetCalendarEvent) - [List calendar events](/developers/reference/meetings/ListCalendarEvents) - [List colleagues](/developers/reference/workspace/ListColleagues) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.UpdateCalendarEvent' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_example", "patch": {} }' ``` #### TypeScript ```typescript 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.UpdateCalendarEvent", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_example", "patch": {} }), }); 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_example", "patch": {} } request = Request( "https://api.brigg.app/v1/operations/meetings.UpdateCalendarEvent", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "id": "e_example", "uid": "kickoff@example.com", "sequence": 1, "significant": false } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "The core:CalendarEvent entry id." }, "patch": { "type": "object", "properties": { "title": { "type": "string", "minLength": 1, "description": "Display title." }, "start": { "type": "string", "description": "Start timestamp with an explicit time zone, for example 2026-11-10T10:00:00+01:00. Brigg normalizes it to UTC. Do not send a date without a time zone." }, "end": { "type": "string", "description": "End timestamp with an explicit time zone, strictly later than start. Returned calendar times use UTC." }, "location": { "type": "string", "description": "Physical address or meeting location supplied to invitees." }, "description": { "type": "string", "description": "Descriptive text." }, "agenda": { "type": "string", "description": "Discussion topics planned for the meeting." }, "notes": { "type": "string", "description": "Notes supplied for the calendar event." }, "attendees": { "type": "array", "items": { "type": "string" }, "description": "Workspace member account IDs from [List colleagues](/developers/reference/workspace/ListColleagues), not Person record IDs or email addresses. Members without an email address are returned in send.skipped." }, "visibility": { "type": "array", "items": { "type": "string" }, "minItems": 1, "description": "Reserved compatibility field; it currently has no effect. Omit it. It cannot make the calendar event private or grant access to attendees." } }, "additionalProperties": false, "description": "Requested changes to the calendar event." }, "send_update": { "type": "boolean", "description": "Mail the updated invitation to every attendee." }, "message": { "type": "string", "description": "Message included with the calendar invitation update or cancellation." } }, "required": [ "id", "patch" ], "additionalProperties": false, "examples": [ { "id": "e_example", "patch": {} } ] } ``` ```json-schema-response { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier. Use the value returned by a create or list operation." }, "uid": { "type": "string", "description": "Calendar invitation UID, distinct from the Brigg record ID." }, "sequence": { "type": "number", "description": "Calendar invitation revision number." }, "significant": { "type": "boolean", "description": "Whether time or place changed." }, "send": { "type": "object", "description": "Present when a mail-out was asked for.", "properties": { "message_ids": { "description": "Recipient email address to delivery message ID.", "type": "object", "additionalProperties": { "type": "string" } }, "skipped": { "type": "array", "items": { "type": "string" }, "description": "Attendee account ids with no email address." }, "rate_limited": { "type": "boolean", "description": "The org's invite quota was hit — the event write landed, no mail went out." } }, "required": [ "message_ids", "skipped" ], "additionalProperties": false } }, "required": [ "id", "uid", "sequence", "significant" ], "additionalProperties": false, "examples": [ { "id": "e_example", "uid": "kickoff@example.com", "sequence": 1, "significant": false } ] } ``` --- # Cancel connected calendar event Propose cancelling an event the acting member organizes on their connected calendar. The member approves the cancellation in Brigg; attendee notifications follow execution. Recurring events are unsupported. POST https://api.brigg.app/v1/operations/meetings.CancelConnectedCalendarEvent ## Access & visibility Allow `meetings.CancelConnectedCalendarEvent` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `event_id` | string | Yes | Brigg CalendarEvent record ID from ListCalendarEvents for this member's connected-provider event. It is not a Meeting ID or raw provider ID. The member must organize the event; recurring occurrences cannot be changed here. At least 1 character. At most 200 characters. | ## Treat this as a proposal, not a completed calendar change API calls are non-interactive proposals, even with approved member delegation. A standing calendar permission does not bypass human approval here. A valid proposal normally returns awaiting_permission and posts a card to the acting member in Brigg. The member can approve or refuse it there; no public operation approves the card. For denied, stop: the member's calendar-action policy refuses the proposal. For done, inspect outcome.status. In particular, done with needs_auth means provider access must be connected or renewed; no calendar change happened. Open the returned auth_url only for that member to complete provider consent. The response schema also represents provider execution outcomes: only outcome.status=done denotes a completed attempt; failed includes reason. Replaying the same idempotency key returns the original proposal response, not live approval status. Do not poll by creating more proposals. After the member acts, check the connected calendar or its synchronized records in [List calendar events](/developers/reference/meetings/ListCalendarEvents); synchronization can lag. If provider consent changed and the member still wants the action, submit a deliberate new proposal with a new key. ## Provider access and action approval [List calendar connections](/developers/reference/meetings/ListCalendarConnections) first. The acting member needs a connected Google or Microsoft account with calendar write permission. The key's grant does not replace the provider's OAuth permission or the member's action policy. API calls propose an action for member approval; a standing setting does not turn an API call into the person's direct action. Inspect `status`, `outcome` and `permission` before treating the action as complete. A response requiring approval must be continued by the member in Brigg; returning an approval card is not evidence that a provider event was written. Retrying with a new idempotency key can create another logical action. For update or cancellation, use the Brigg record ID of the synchronized event, not a raw provider ID. A Brigg-owned event without a connected-provider identity uses the separate calendar-event operations. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `status` | string | Yes | Proposal state: awaiting_permission requires the member's decision in Brigg; denied means their policy refused it; done requires inspecting outcome.status and does not itself prove a calendar write. Allowed: `"done"`, `"awaiting_permission"`, `"denied"`. | | `outcome` | [object](#response-outcome) | No | Execution or provider-authorization result when top-level status is done. Missing on an awaiting_permission response. | | `card` | [CalendarApprovalCard](#calendarapprovalcard-response-card) | No | Approval card delivered to the acting member in Brigg. This is a proposal, not permission granted to the integration. | | `permission` | string | No | The refused action policy. Calendar proposals use create_calendar_event, including updates and cancellations. | ### response.outcome | Field | Type | Required | Description | | --- | --- | --- | --- | | `status` | string | Yes | done denotes a completed provider attempt; failed reports reason; needs_auth requires member provider consent before a new proposal can proceed. Allowed: `"done"`, `"failed"`, `"needs_auth"`. | | `reason` | string | No | Machine-readable cause, such as missing_scope, no_connection, rate_limited or provider_error. Treat the reason set as extensible; do not assume failed is safe to repeat blindly. | | `auth_url` | string | No | Member-only continuation URL when outcome.status=needs_auth. Open it for the same acting member to connect or renew provider access; do not fetch it with the API key. | | `job_id` | string | No | Optional shared action-result field. Calendar proposals do not return a polling job through this field; do not wait for it. | ### CalendarApprovalCard · response.card | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Identifier of the approval card. No public API accepts this ID to approve it or poll its decision. | | `kind` | string | Yes | Category identifying which variant of this model applies. Always `"card_agent_permission"`. | | `payload` | [object](#response-card-payload) | Yes | Action details shown for approval when the calendar policy requires review. | ### response.card.payload | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Category identifying which variant of this model applies. Always `"card_agent_permission"`. | | `permission` | string | Yes | create_calendar_event for this calendar action. Other values belong to the shared card schema. Allowed: `"create_calendar_event"`, `"send_email"`, `"email_people"`, `"text_people"`, `"place_calls"`, `"use_browser"`. | | `action` | [object (8 variants)](#response-card-payload-action) | Yes | The proposed calendar change. Only kind=cancel_calendar_event applies to this operation; other variants belong to the shared approval-card schema. | ### response.card.payload.action #### kind = "browser_task" | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Category identifying which variant of this model applies. Always `"browser_task"`. | | `goal` | string | Yes | Purpose the proposed agenda should help achieve. | | `start_url` | string | No | URL where the acting member begins the connection flow. | | `context` | string | No | Background information available for preparing the agenda. | | `attachments` | array of [object](#response-card-payload-action-variant1-attachments) | No | Attachments supplied for the related action. | | `keep_tab_open` | boolean | No | Whether the connection flow requires its browser tab to remain open. Allowed: `false`, `true`. | ### response.card.payload.action.variant1.attachments[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `file_id` | string | Yes | File identifier. | | `name` | string | Yes | Display name. | #### kind = "place_call" | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Category identifying which variant of this model applies. Always `"place_call"`. | | `to` | string | Yes | Recipients of the related message or calendar action. | | `name` | null or string | Yes | Display name. | | `brief` | string | Yes | Preparation summary for the upcoming meeting. | | `record_id` | string | No | Record identifier. | #### kind = "send_sms" | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Category identifying which variant of this model applies. Always `"send_sms"`. | | `to` | string | Yes | Recipients of the related message or calendar action. | | `name` | string | Yes | Display name. | | `text` | string | Yes | Text content. | | `record_id` | string | No | Record identifier. | | `unknown_recipient` | boolean | No | Whether the action includes a recipient not already recognized by the caller's policy. Allowed: `false`, `true`. | #### kind = "contact_person" | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Category identifying which variant of this model applies. Always `"contact_person"`. | | `to` | string | Yes | Recipients of the related message or calendar action. | | `subject` | string | Yes | Title or subject supplied for this calendar action. | | `body` | string | Yes | Descriptive content supplied for the calendar action. | | `instruction` | string | No | Instructions to use when preparing the requested meeting content. | #### kind = "send_email" | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Category identifying which variant of this model applies. Always `"send_email"`. | | `to` | array of string | Yes | Recipients of the related message or calendar action. | | `cc` | array of string | No | Recipients to copy on the related message. | | `subject` | string | Yes | Title or subject supplied for this calendar action. | | `body` | string | Yes | Descriptive content supplied for the calendar action. | #### kind = "create_calendar_event" | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Category identifying which variant of this model applies. Always `"create_calendar_event"`. | | `title` | string | Yes | Display title. | | `start` | string | Yes | Start of the interval. | | `end` | string | Yes | End of the interval; must be later than its start. | | `attendees` | array of string | No | People invited to the event and their invitation details. | | `add_conference` | boolean | No | Whether to request a video-conference link from the connected calendar provider. Allowed: `false`, `true`. | | `provider` | string | No | Connected calendar provider used for this action. Allowed: `"google"`, `"microsoft"`. | #### kind = "update_calendar_event" | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Category identifying which variant of this model applies. Always `"update_calendar_event"`. | | `event_id` | string | Yes | The same Brigg CalendarEvent record ID supplied as event_id. The card uses camelCase. | | `current` | [object](#response-card-payload-action-variant7-current) | Yes | Snapshot of the synchronized event when the proposal was prepared, not a promise that the event cannot change before approval. | | `title` | string | No | Display title. | | `start` | string | No | Start of the interval. | | `end` | string | No | End of the interval; must be later than its start. | ### response.card.payload.action.variant7.current | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string | Yes | Display title. | | `start` | string | Yes | Start of the interval. | | `end` | string | Yes | End of the interval; must be later than its start. | #### kind = "cancel_calendar_event" | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Category identifying which variant of this model applies. Always `"cancel_calendar_event"`. | | `event_id` | string | Yes | The same Brigg CalendarEvent record ID supplied as event_id. The card uses camelCase. | | `current` | [object](#response-card-payload-action-variant8-current) | Yes | Snapshot of the synchronized event when the proposal was prepared, not a promise that the event cannot change before approval. | ### response.card.payload.action.variant8.current | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string | Yes | Display title. | | `start` | string | Yes | Start of the interval. | | `end` | string | Yes | End of the interval; must be later than its start. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | | 400 | `event_not_found` | Choose the acting member's synchronized CalendarEvent ID, not a Meeting ID. | | 400 | `not_organizer` | Only the event's organizer can change it. Ask the organizer to act. | | 400 | `recurring_event` | Edit repeating events in the provider calendar; this API does not change occurrences or series. | ## Next steps - [List calendar connections](/developers/reference/meetings/ListCalendarConnections) - [List calendar events](/developers/reference/meetings/ListCalendarEvents) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Member approval is required HTTP 200 means the proposal was processed. No provider event has been changed yet. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.CancelConnectedCalendarEvent' \ -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 '{ "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.CancelConnectedCalendarEvent", { 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({ "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 = { "event_id": "e_calendar_kickoff" } request = Request( "https://api.brigg.app/v1/operations/meetings.CancelConnectedCalendarEvent", 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 { "status": "awaiting_permission", "card": { "id": "card_calendar_proposal", "kind": "card_agent_permission", "payload": { "kind": "card_agent_permission", "permission": "create_calendar_event", "action": { "kind": "cancel_calendar_event", "event_id": "e_calendar_kickoff", "current": { "title": "Northstar project kickoff", "start": "2026-11-10T09:00:00.000Z", "end": "2026-11-10T09:45:00.000Z" } } } } } ``` ### The member's policy refuses the action Stop here. Broader key grants do not override the member's action policy. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.CancelConnectedCalendarEvent' \ -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 '{ "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.CancelConnectedCalendarEvent", { 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({ "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 = { "event_id": "e_calendar_kickoff" } request = Request( "https://api.brigg.app/v1/operations/meetings.CancelConnectedCalendarEvent", 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 { "status": "denied", "permission": "create_calendar_event" } ``` ### Provider consent needs attention This does not cancel or update the event. The acting member must complete the provider connection first. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.CancelConnectedCalendarEvent' \ -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 '{ "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.CancelConnectedCalendarEvent", { 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({ "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 = { "event_id": "e_calendar_kickoff" } request = Request( "https://api.brigg.app/v1/operations/meetings.CancelConnectedCalendarEvent", 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 { "status": "done", "outcome": { "status": "needs_auth", "reason": "missing_scope", "auth_url": "https://app.example.com/account" } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "event_id": { "type": "string", "minLength": 1, "maxLength": 200, "description": "Brigg CalendarEvent record ID from ListCalendarEvents for this member's connected-provider event. It is not a Meeting ID or raw provider ID. The member must organize the event; recurring occurrences cannot be changed here." } }, "required": [ "event_id" ], "additionalProperties": false, "examples": [ { "event_id": "e_calendar_kickoff" } ] } ``` ```json-schema-response { "type": "object", "description": "done means the policy allowed an attempt: inspect outcome.status for the provider result. awaiting_permission means a person must approve the action in Brigg. denied means the member's policy refused it. An approval response is not a completed provider write.", "properties": { "status": { "type": "string", "enum": [ "done", "awaiting_permission", "denied" ], "description": "Proposal state: awaiting_permission requires the member's decision in Brigg; denied means their policy refused it; done requires inspecting outcome.status and does not itself prove a calendar write." }, "outcome": { "type": "object", "properties": { "status": { "type": "string", "enum": [ "done", "failed", "needs_auth" ], "description": "done denotes a completed provider attempt; failed reports reason; needs_auth requires member provider consent before a new proposal can proceed." }, "reason": { "type": "string", "description": "Machine-readable cause, such as missing_scope, no_connection, rate_limited or provider_error. Treat the reason set as extensible; do not assume failed is safe to repeat blindly." }, "auth_url": { "type": "string", "description": "Member-only continuation URL when outcome.status=needs_auth. Open it for the same acting member to connect or renew provider access; do not fetch it with the API key." }, "job_id": { "type": "string", "description": "Optional shared action-result field. Calendar proposals do not return a polling job through this field; do not wait for it." } }, "required": [ "status" ], "additionalProperties": false, "description": "Execution or provider-authorization result when top-level status is done. Missing on an awaiting_permission response." }, "card": { "description": "Approval card delivered to the acting member in Brigg. This is a proposal, not permission granted to the integration.", "title": "CalendarApprovalCard", "type": "object", "properties": { "id": { "type": "string", "description": "Identifier of the approval card. No public API accepts this ID to approve it or poll its decision." }, "kind": { "type": "string", "const": "card_agent_permission", "description": "Category identifying which variant of this model applies." }, "payload": { "type": "object", "properties": { "kind": { "type": "string", "const": "card_agent_permission", "description": "Category identifying which variant of this model applies." }, "permission": { "type": "string", "enum": [ "create_calendar_event", "send_email", "email_people", "text_people", "place_calls", "use_browser" ], "description": "create_calendar_event for this calendar action. Other values belong to the shared card schema." }, "action": { "anyOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "browser_task", "description": "Category identifying which variant of this model applies." }, "goal": { "type": "string", "description": "Purpose the proposed agenda should help achieve." }, "start_url": { "type": "string", "description": "URL where the acting member begins the connection flow." }, "context": { "type": "string", "description": "Background information available for preparing the agenda." }, "attachments": { "type": "array", "items": { "type": "object", "properties": { "file_id": { "type": "string", "description": "File identifier." }, "name": { "type": "string", "description": "Display name." } }, "required": [ "file_id", "name" ], "additionalProperties": false }, "description": "Attachments supplied for the related action." }, "keep_tab_open": { "type": "boolean", "enum": [ false, true ], "description": "Whether the connection flow requires its browser tab to remain open." } }, "required": [ "kind", "goal" ], "additionalProperties": false, "description": "The proposed calendar change. Only kind=cancel_calendar_event applies to this operation; other variants belong to the shared approval-card schema." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "place_call", "description": "Category identifying which variant of this model applies." }, "to": { "type": "string", "description": "Recipients of the related message or calendar action." }, "name": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Display name." }, "brief": { "type": "string", "description": "Preparation summary for the upcoming meeting." }, "record_id": { "type": "string", "description": "Record identifier." } }, "required": [ "kind", "to", "name", "brief" ], "additionalProperties": false, "description": "The proposed calendar change. Only kind=cancel_calendar_event applies to this operation; other variants belong to the shared approval-card schema." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "send_sms", "description": "Category identifying which variant of this model applies." }, "to": { "type": "string", "description": "Recipients of the related message or calendar action." }, "name": { "type": "string", "description": "Display name." }, "text": { "type": "string", "description": "Text content." }, "record_id": { "type": "string", "description": "Record identifier." }, "unknown_recipient": { "type": "boolean", "enum": [ false, true ], "description": "Whether the action includes a recipient not already recognized by the caller's policy." } }, "required": [ "kind", "to", "name", "text" ], "additionalProperties": false, "description": "The proposed calendar change. Only kind=cancel_calendar_event applies to this operation; other variants belong to the shared approval-card schema." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "contact_person", "description": "Category identifying which variant of this model applies." }, "to": { "type": "string", "description": "Recipients of the related message or calendar action." }, "subject": { "type": "string", "description": "Title or subject supplied for this calendar action." }, "body": { "type": "string", "description": "Descriptive content supplied for the calendar action." }, "instruction": { "type": "string", "description": "Instructions to use when preparing the requested meeting content." } }, "required": [ "kind", "to", "subject", "body" ], "additionalProperties": false, "description": "The proposed calendar change. Only kind=cancel_calendar_event applies to this operation; other variants belong to the shared approval-card schema." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "send_email", "description": "Category identifying which variant of this model applies." }, "to": { "type": "array", "items": { "type": "string" }, "description": "Recipients of the related message or calendar action." }, "cc": { "type": "array", "items": { "type": "string" }, "description": "Recipients to copy on the related message." }, "subject": { "type": "string", "description": "Title or subject supplied for this calendar action." }, "body": { "type": "string", "description": "Descriptive content supplied for the calendar action." } }, "required": [ "kind", "to", "subject", "body" ], "additionalProperties": false, "description": "The proposed calendar change. Only kind=cancel_calendar_event applies to this operation; other variants belong to the shared approval-card schema." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "create_calendar_event", "description": "Category identifying which variant of this model applies." }, "title": { "type": "string", "description": "Display title." }, "start": { "type": "string", "description": "Start of the interval." }, "end": { "type": "string", "description": "End of the interval; must be later than its start." }, "attendees": { "type": "array", "items": { "type": "string" }, "description": "People invited to the event and their invitation details." }, "add_conference": { "type": "boolean", "enum": [ false, true ], "description": "Whether to request a video-conference link from the connected calendar provider." }, "provider": { "type": "string", "enum": [ "google", "microsoft" ], "description": "Connected calendar provider used for this action." } }, "required": [ "kind", "title", "start", "end" ], "additionalProperties": false, "description": "The proposed calendar change. Only kind=cancel_calendar_event applies to this operation; other variants belong to the shared approval-card schema." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "update_calendar_event", "description": "Category identifying which variant of this model applies." }, "event_id": { "type": "string", "description": "The same Brigg CalendarEvent record ID supplied as event_id. The card uses camelCase." }, "current": { "type": "object", "properties": { "title": { "type": "string", "description": "Display title." }, "start": { "type": "string", "description": "Start of the interval." }, "end": { "type": "string", "description": "End of the interval; must be later than its start." } }, "required": [ "title", "start", "end" ], "additionalProperties": false, "description": "Snapshot of the synchronized event when the proposal was prepared, not a promise that the event cannot change before approval." }, "title": { "type": "string", "description": "Display title." }, "start": { "type": "string", "description": "Start of the interval." }, "end": { "type": "string", "description": "End of the interval; must be later than its start." } }, "required": [ "kind", "event_id", "current" ], "additionalProperties": false, "description": "The proposed calendar change. Only kind=cancel_calendar_event applies to this operation; other variants belong to the shared approval-card schema." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "cancel_calendar_event", "description": "Category identifying which variant of this model applies." }, "event_id": { "type": "string", "description": "The same Brigg CalendarEvent record ID supplied as event_id. The card uses camelCase." }, "current": { "type": "object", "properties": { "title": { "type": "string", "description": "Display title." }, "start": { "type": "string", "description": "Start of the interval." }, "end": { "type": "string", "description": "End of the interval; must be later than its start." } }, "required": [ "title", "start", "end" ], "additionalProperties": false, "description": "Snapshot of the synchronized event when the proposal was prepared, not a promise that the event cannot change before approval." } }, "required": [ "kind", "event_id", "current" ], "additionalProperties": false, "description": "The proposed calendar change. Only kind=cancel_calendar_event applies to this operation; other variants belong to the shared approval-card schema." } ], "description": "The proposed calendar change. Only kind=cancel_calendar_event applies to this operation; other variants belong to the shared approval-card schema." } }, "required": [ "kind", "permission", "action" ], "additionalProperties": false, "description": "Action details shown for approval when the calendar policy requires review." } }, "required": [ "id", "kind", "payload" ], "additionalProperties": false }, "permission": { "type": "string", "description": "The refused action policy. Calendar proposals use create_calendar_event, including updates and cancellations." } }, "required": [ "status" ], "additionalProperties": false, "examples": [ { "status": "awaiting_permission", "card": { "id": "card_calendar_proposal", "kind": "card_agent_permission", "payload": { "kind": "card_agent_permission", "permission": "create_calendar_event", "action": { "kind": "cancel_calendar_event", "event_id": "e_calendar_kickoff", "current": { "title": "Northstar project kickoff", "start": "2026-11-10T09:00:00.000Z", "end": "2026-11-10T09:45:00.000Z" } } } } } ] } ``` --- # Create connected calendar event Propose creating an event on the acting member's connected Google or Microsoft calendar, with invitations and an optional video link. The member approves the action in Brigg before it is performed. POST https://api.brigg.app/v1/operations/meetings.CreateConnectedCalendarEvent ## Access & visibility Allow `meetings.CreateConnectedCalendarEvent` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `title` | string | Yes | Display title. At least 1 character. At most 500 characters. | | `start` | string | Yes | ISO 8601 start with an explicit time zone. For an update supply both start and end, or neither. | | `end` | string | Yes | ISO 8601 end with an explicit time zone, later than start. Updating only one boundary is refused. | | `attendees` | array of string | No | Invitee email addresses for the connected provider, not workspace account IDs. Invitation delivery follows member approval. At most 100 items. | | `add_conference` | boolean | No | Attach a Meet/Teams link (default true). | | `provider` | string | No | Choose an enabled connection with calendar write permission. Provider permissions and the member's Brigg action policy both apply. [meetings.ListCalendarConnections](/developers/reference/meetings/ListCalendarConnections). Allowed: `"google"`, `"microsoft"`. | ## Treat this as a proposal, not a completed calendar change API calls are non-interactive proposals, even with approved member delegation. A standing calendar permission does not bypass human approval here. A valid proposal normally returns awaiting_permission and posts a card to the acting member in Brigg. The member can approve or refuse it there; no public operation approves the card. For denied, stop: the member's calendar-action policy refuses the proposal. For done, inspect outcome.status. In particular, done with needs_auth means provider access must be connected or renewed; no calendar change happened. Open the returned auth_url only for that member to complete provider consent. The response schema also represents provider execution outcomes: only outcome.status=done denotes a completed attempt; failed includes reason. Replaying the same idempotency key returns the original proposal response, not live approval status. Do not poll by creating more proposals. After the member acts, check the connected calendar or its synchronized records in [List calendar events](/developers/reference/meetings/ListCalendarEvents); synchronization can lag. If provider consent changed and the member still wants the action, submit a deliberate new proposal with a new key. ## Provider access and action approval [List calendar connections](/developers/reference/meetings/ListCalendarConnections) first. The acting member needs a connected Google or Microsoft account with calendar write permission. The key's grant does not replace the provider's OAuth permission or the member's action policy. API calls propose an action for member approval; a standing setting does not turn an API call into the person's direct action. Inspect `status`, `outcome` and `permission` before treating the action as complete. A response requiring approval must be continued by the member in Brigg; returning an approval card is not evidence that a provider event was written. Retrying with a new idempotency key can create another logical action. For update or cancellation, use the Brigg record ID of the synchronized event, not a raw provider ID. A Brigg-owned event without a connected-provider identity uses the separate calendar-event operations. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `status` | string | Yes | Proposal state: awaiting_permission requires the member's decision in Brigg; denied means their policy refused it; done requires inspecting outcome.status and does not itself prove a calendar write. Allowed: `"done"`, `"awaiting_permission"`, `"denied"`. | | `outcome` | [object](#response-outcome) | No | Execution or provider-authorization result when top-level status is done. Missing on an awaiting_permission response. | | `card` | [CalendarApprovalCard](#calendarapprovalcard-response-card) | No | Approval card delivered to the acting member in Brigg. This is a proposal, not permission granted to the integration. | | `permission` | string | No | The refused action policy. Calendar proposals use create_calendar_event, including updates and cancellations. | ### response.outcome | Field | Type | Required | Description | | --- | --- | --- | --- | | `status` | string | Yes | done denotes a completed provider attempt; failed reports reason; needs_auth requires member provider consent before a new proposal can proceed. Allowed: `"done"`, `"failed"`, `"needs_auth"`. | | `reason` | string | No | Machine-readable cause, such as missing_scope, no_connection, rate_limited or provider_error. Treat the reason set as extensible; do not assume failed is safe to repeat blindly. | | `auth_url` | string | No | Member-only continuation URL when outcome.status=needs_auth. Open it for the same acting member to connect or renew provider access; do not fetch it with the API key. | | `job_id` | string | No | Optional shared action-result field. Calendar proposals do not return a polling job through this field; do not wait for it. | ### CalendarApprovalCard · response.card | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Identifier of the approval card. No public API accepts this ID to approve it or poll its decision. | | `kind` | string | Yes | Category identifying which variant of this model applies. Always `"card_agent_permission"`. | | `payload` | [object](#response-card-payload) | Yes | Action details shown for approval when the calendar policy requires review. | ### response.card.payload | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Category identifying which variant of this model applies. Always `"card_agent_permission"`. | | `permission` | string | Yes | create_calendar_event for this calendar action. Other values belong to the shared card schema. Allowed: `"create_calendar_event"`, `"send_email"`, `"email_people"`, `"text_people"`, `"place_calls"`, `"use_browser"`. | | `action` | [object (8 variants)](#response-card-payload-action) | Yes | The proposed calendar change. Only kind=create_calendar_event applies to this operation; other variants belong to the shared approval-card schema. | ### response.card.payload.action #### kind = "browser_task" | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Category identifying which variant of this model applies. Always `"browser_task"`. | | `goal` | string | Yes | Purpose the proposed agenda should help achieve. | | `start_url` | string | No | URL where the acting member begins the connection flow. | | `context` | string | No | Background information available for preparing the agenda. | | `attachments` | array of [object](#response-card-payload-action-variant1-attachments) | No | Attachments supplied for the related action. | | `keep_tab_open` | boolean | No | Whether the connection flow requires its browser tab to remain open. Allowed: `false`, `true`. | ### response.card.payload.action.variant1.attachments[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `file_id` | string | Yes | File identifier. | | `name` | string | Yes | Display name. | #### kind = "place_call" | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Category identifying which variant of this model applies. Always `"place_call"`. | | `to` | string | Yes | Recipients of the related message or calendar action. | | `name` | null or string | Yes | Display name. | | `brief` | string | Yes | Preparation summary for the upcoming meeting. | | `record_id` | string | No | Record identifier. | #### kind = "send_sms" | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Category identifying which variant of this model applies. Always `"send_sms"`. | | `to` | string | Yes | Recipients of the related message or calendar action. | | `name` | string | Yes | Display name. | | `text` | string | Yes | Text content. | | `record_id` | string | No | Record identifier. | | `unknown_recipient` | boolean | No | Whether the action includes a recipient not already recognized by the caller's policy. Allowed: `false`, `true`. | #### kind = "contact_person" | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Category identifying which variant of this model applies. Always `"contact_person"`. | | `to` | string | Yes | Recipients of the related message or calendar action. | | `subject` | string | Yes | Title or subject supplied for this calendar action. | | `body` | string | Yes | Descriptive content supplied for the calendar action. | | `instruction` | string | No | Instructions to use when preparing the requested meeting content. | #### kind = "send_email" | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Category identifying which variant of this model applies. Always `"send_email"`. | | `to` | array of string | Yes | Recipients of the related message or calendar action. | | `cc` | array of string | No | Recipients to copy on the related message. | | `subject` | string | Yes | Title or subject supplied for this calendar action. | | `body` | string | Yes | Descriptive content supplied for the calendar action. | #### kind = "create_calendar_event" | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Category identifying which variant of this model applies. Always `"create_calendar_event"`. | | `title` | string | Yes | Display title. | | `start` | string | Yes | Start of the interval. | | `end` | string | Yes | End of the interval; must be later than its start. | | `attendees` | array of string | No | People invited to the event and their invitation details. | | `add_conference` | boolean | No | Whether to request a video-conference link from the connected calendar provider. Allowed: `false`, `true`. | | `provider` | string | No | Connected calendar provider used for this action. Allowed: `"google"`, `"microsoft"`. | #### kind = "update_calendar_event" | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Category identifying which variant of this model applies. Always `"update_calendar_event"`. | | `event_id` | string | Yes | The same Brigg CalendarEvent record ID supplied as event_id. The card uses camelCase. | | `current` | [object](#response-card-payload-action-variant7-current) | Yes | Snapshot of the synchronized event when the proposal was prepared, not a promise that the event cannot change before approval. | | `title` | string | No | Display title. | | `start` | string | No | Start of the interval. | | `end` | string | No | End of the interval; must be later than its start. | ### response.card.payload.action.variant7.current | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string | Yes | Display title. | | `start` | string | Yes | Start of the interval. | | `end` | string | Yes | End of the interval; must be later than its start. | #### kind = "cancel_calendar_event" | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Category identifying which variant of this model applies. Always `"cancel_calendar_event"`. | | `event_id` | string | Yes | The same Brigg CalendarEvent record ID supplied as event_id. The card uses camelCase. | | `current` | [object](#response-card-payload-action-variant8-current) | Yes | Snapshot of the synchronized event when the proposal was prepared, not a promise that the event cannot change before approval. | ### response.card.payload.action.variant8.current | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string | Yes | Display title. | | `start` | string | Yes | Start of the interval. | | `end` | string | Yes | End of the interval; must be later than its start. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | | 400 | `invalid_range` | Use an end after start with explicit time zones. | | 400 | `invalid_action` | An update must change a title or supply both start and end. | ## Next steps - [List calendar connections](/developers/reference/meetings/ListCalendarConnections) - [List calendar events](/developers/reference/meetings/ListCalendarEvents) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Member approval is required HTTP 200 means the proposal was processed. No provider event has been changed yet. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.CreateConnectedCalendarEvent' \ -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 '{ "title": "Northstar project kickoff", "start": "2026-11-10T09:00:00.000Z", "end": "2026-11-10T09:45:00.000Z", "attendees": [ "alex@example.com" ] }' ``` #### 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.CreateConnectedCalendarEvent", { 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({ "title": "Northstar project kickoff", "start": "2026-11-10T09:00:00.000Z", "end": "2026-11-10T09:45:00.000Z", "attendees": [ "alex@example.com" ] }), }); 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 = { "title": "Northstar project kickoff", "start": "2026-11-10T09:00:00.000Z", "end": "2026-11-10T09:45:00.000Z", "attendees": [ "alex@example.com" ] } request = Request( "https://api.brigg.app/v1/operations/meetings.CreateConnectedCalendarEvent", 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 { "status": "awaiting_permission", "card": { "id": "card_calendar_proposal", "kind": "card_agent_permission", "payload": { "kind": "card_agent_permission", "permission": "create_calendar_event", "action": { "kind": "create_calendar_event", "title": "Northstar project kickoff", "start": "2026-11-10T09:00:00.000Z", "end": "2026-11-10T09:45:00.000Z", "attendees": [ "alex@example.com" ] } } } } ``` ### The member's policy refuses the action Stop here. Broader key grants do not override the member's action policy. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.CreateConnectedCalendarEvent' \ -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 '{ "title": "Northstar project kickoff", "start": "2026-11-10T09:00:00.000Z", "end": "2026-11-10T09:45:00.000Z", "attendees": [ "alex@example.com" ] }' ``` #### 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.CreateConnectedCalendarEvent", { 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({ "title": "Northstar project kickoff", "start": "2026-11-10T09:00:00.000Z", "end": "2026-11-10T09:45:00.000Z", "attendees": [ "alex@example.com" ] }), }); 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 = { "title": "Northstar project kickoff", "start": "2026-11-10T09:00:00.000Z", "end": "2026-11-10T09:45:00.000Z", "attendees": [ "alex@example.com" ] } request = Request( "https://api.brigg.app/v1/operations/meetings.CreateConnectedCalendarEvent", 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 { "status": "denied", "permission": "create_calendar_event" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "title": { "type": "string", "minLength": 1, "maxLength": 500, "description": "Display title." }, "start": { "type": "string", "description": "ISO 8601 start with an explicit time zone. For an update supply both start and end, or neither." }, "end": { "type": "string", "description": "ISO 8601 end with an explicit time zone, later than start. Updating only one boundary is refused." }, "attendees": { "type": "array", "items": { "type": "string", "format": "email" }, "maxItems": 100, "description": "Invitee email addresses for the connected provider, not workspace account IDs. Invitation delivery follows member approval." }, "add_conference": { "type": "boolean", "description": "Attach a Meet/Teams link (default true)." }, "provider": { "type": "string", "enum": [ "google", "microsoft" ], "description": "Choose an enabled connection with calendar write permission. Provider permissions and the member's Brigg action policy both apply. [meetings.ListCalendarConnections](/developers/reference/meetings/ListCalendarConnections)." } }, "required": [ "title", "start", "end" ], "additionalProperties": false, "examples": [ { "title": "Northstar project kickoff", "start": "2026-11-10T09:00:00.000Z", "end": "2026-11-10T09:45:00.000Z", "attendees": [ "alex@example.com" ] } ] } ``` ```json-schema-response { "type": "object", "description": "done means the policy allowed an attempt: inspect outcome.status for the provider result. awaiting_permission means a person must approve the action in Brigg. denied means the member's policy refused it. An approval response is not a completed provider write.", "properties": { "status": { "type": "string", "enum": [ "done", "awaiting_permission", "denied" ], "description": "Proposal state: awaiting_permission requires the member's decision in Brigg; denied means their policy refused it; done requires inspecting outcome.status and does not itself prove a calendar write." }, "outcome": { "type": "object", "properties": { "status": { "type": "string", "enum": [ "done", "failed", "needs_auth" ], "description": "done denotes a completed provider attempt; failed reports reason; needs_auth requires member provider consent before a new proposal can proceed." }, "reason": { "type": "string", "description": "Machine-readable cause, such as missing_scope, no_connection, rate_limited or provider_error. Treat the reason set as extensible; do not assume failed is safe to repeat blindly." }, "auth_url": { "type": "string", "description": "Member-only continuation URL when outcome.status=needs_auth. Open it for the same acting member to connect or renew provider access; do not fetch it with the API key." }, "job_id": { "type": "string", "description": "Optional shared action-result field. Calendar proposals do not return a polling job through this field; do not wait for it." } }, "required": [ "status" ], "additionalProperties": false, "description": "Execution or provider-authorization result when top-level status is done. Missing on an awaiting_permission response." }, "card": { "description": "Approval card delivered to the acting member in Brigg. This is a proposal, not permission granted to the integration.", "title": "CalendarApprovalCard", "type": "object", "properties": { "id": { "type": "string", "description": "Identifier of the approval card. No public API accepts this ID to approve it or poll its decision." }, "kind": { "type": "string", "const": "card_agent_permission", "description": "Category identifying which variant of this model applies." }, "payload": { "type": "object", "properties": { "kind": { "type": "string", "const": "card_agent_permission", "description": "Category identifying which variant of this model applies." }, "permission": { "type": "string", "enum": [ "create_calendar_event", "send_email", "email_people", "text_people", "place_calls", "use_browser" ], "description": "create_calendar_event for this calendar action. Other values belong to the shared card schema." }, "action": { "anyOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "browser_task", "description": "Category identifying which variant of this model applies." }, "goal": { "type": "string", "description": "Purpose the proposed agenda should help achieve." }, "start_url": { "type": "string", "description": "URL where the acting member begins the connection flow." }, "context": { "type": "string", "description": "Background information available for preparing the agenda." }, "attachments": { "type": "array", "items": { "type": "object", "properties": { "file_id": { "type": "string", "description": "File identifier." }, "name": { "type": "string", "description": "Display name." } }, "required": [ "file_id", "name" ], "additionalProperties": false }, "description": "Attachments supplied for the related action." }, "keep_tab_open": { "type": "boolean", "enum": [ false, true ], "description": "Whether the connection flow requires its browser tab to remain open." } }, "required": [ "kind", "goal" ], "additionalProperties": false, "description": "The proposed calendar change. Only kind=create_calendar_event applies to this operation; other variants belong to the shared approval-card schema." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "place_call", "description": "Category identifying which variant of this model applies." }, "to": { "type": "string", "description": "Recipients of the related message or calendar action." }, "name": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Display name." }, "brief": { "type": "string", "description": "Preparation summary for the upcoming meeting." }, "record_id": { "type": "string", "description": "Record identifier." } }, "required": [ "kind", "to", "name", "brief" ], "additionalProperties": false, "description": "The proposed calendar change. Only kind=create_calendar_event applies to this operation; other variants belong to the shared approval-card schema." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "send_sms", "description": "Category identifying which variant of this model applies." }, "to": { "type": "string", "description": "Recipients of the related message or calendar action." }, "name": { "type": "string", "description": "Display name." }, "text": { "type": "string", "description": "Text content." }, "record_id": { "type": "string", "description": "Record identifier." }, "unknown_recipient": { "type": "boolean", "enum": [ false, true ], "description": "Whether the action includes a recipient not already recognized by the caller's policy." } }, "required": [ "kind", "to", "name", "text" ], "additionalProperties": false, "description": "The proposed calendar change. Only kind=create_calendar_event applies to this operation; other variants belong to the shared approval-card schema." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "contact_person", "description": "Category identifying which variant of this model applies." }, "to": { "type": "string", "description": "Recipients of the related message or calendar action." }, "subject": { "type": "string", "description": "Title or subject supplied for this calendar action." }, "body": { "type": "string", "description": "Descriptive content supplied for the calendar action." }, "instruction": { "type": "string", "description": "Instructions to use when preparing the requested meeting content." } }, "required": [ "kind", "to", "subject", "body" ], "additionalProperties": false, "description": "The proposed calendar change. Only kind=create_calendar_event applies to this operation; other variants belong to the shared approval-card schema." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "send_email", "description": "Category identifying which variant of this model applies." }, "to": { "type": "array", "items": { "type": "string" }, "description": "Recipients of the related message or calendar action." }, "cc": { "type": "array", "items": { "type": "string" }, "description": "Recipients to copy on the related message." }, "subject": { "type": "string", "description": "Title or subject supplied for this calendar action." }, "body": { "type": "string", "description": "Descriptive content supplied for the calendar action." } }, "required": [ "kind", "to", "subject", "body" ], "additionalProperties": false, "description": "The proposed calendar change. Only kind=create_calendar_event applies to this operation; other variants belong to the shared approval-card schema." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "create_calendar_event", "description": "Category identifying which variant of this model applies." }, "title": { "type": "string", "description": "Display title." }, "start": { "type": "string", "description": "Start of the interval." }, "end": { "type": "string", "description": "End of the interval; must be later than its start." }, "attendees": { "type": "array", "items": { "type": "string" }, "description": "People invited to the event and their invitation details." }, "add_conference": { "type": "boolean", "enum": [ false, true ], "description": "Whether to request a video-conference link from the connected calendar provider." }, "provider": { "type": "string", "enum": [ "google", "microsoft" ], "description": "Connected calendar provider used for this action." } }, "required": [ "kind", "title", "start", "end" ], "additionalProperties": false, "description": "The proposed calendar change. Only kind=create_calendar_event applies to this operation; other variants belong to the shared approval-card schema." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "update_calendar_event", "description": "Category identifying which variant of this model applies." }, "event_id": { "type": "string", "description": "The same Brigg CalendarEvent record ID supplied as event_id. The card uses camelCase." }, "current": { "type": "object", "properties": { "title": { "type": "string", "description": "Display title." }, "start": { "type": "string", "description": "Start of the interval." }, "end": { "type": "string", "description": "End of the interval; must be later than its start." } }, "required": [ "title", "start", "end" ], "additionalProperties": false, "description": "Snapshot of the synchronized event when the proposal was prepared, not a promise that the event cannot change before approval." }, "title": { "type": "string", "description": "Display title." }, "start": { "type": "string", "description": "Start of the interval." }, "end": { "type": "string", "description": "End of the interval; must be later than its start." } }, "required": [ "kind", "event_id", "current" ], "additionalProperties": false, "description": "The proposed calendar change. Only kind=create_calendar_event applies to this operation; other variants belong to the shared approval-card schema." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "cancel_calendar_event", "description": "Category identifying which variant of this model applies." }, "event_id": { "type": "string", "description": "The same Brigg CalendarEvent record ID supplied as event_id. The card uses camelCase." }, "current": { "type": "object", "properties": { "title": { "type": "string", "description": "Display title." }, "start": { "type": "string", "description": "Start of the interval." }, "end": { "type": "string", "description": "End of the interval; must be later than its start." } }, "required": [ "title", "start", "end" ], "additionalProperties": false, "description": "Snapshot of the synchronized event when the proposal was prepared, not a promise that the event cannot change before approval." } }, "required": [ "kind", "event_id", "current" ], "additionalProperties": false, "description": "The proposed calendar change. Only kind=create_calendar_event applies to this operation; other variants belong to the shared approval-card schema." } ], "description": "The proposed calendar change. Only kind=create_calendar_event applies to this operation; other variants belong to the shared approval-card schema." } }, "required": [ "kind", "permission", "action" ], "additionalProperties": false, "description": "Action details shown for approval when the calendar policy requires review." } }, "required": [ "id", "kind", "payload" ], "additionalProperties": false }, "permission": { "type": "string", "description": "The refused action policy. Calendar proposals use create_calendar_event, including updates and cancellations." } }, "required": [ "status" ], "additionalProperties": false, "examples": [ { "status": "awaiting_permission", "card": { "id": "card_calendar_proposal", "kind": "card_agent_permission", "payload": { "kind": "card_agent_permission", "permission": "create_calendar_event", "action": { "kind": "create_calendar_event", "title": "Northstar project kickoff", "start": "2026-11-10T09:00:00.000Z", "end": "2026-11-10T09:45:00.000Z", "attendees": [ "alex@example.com" ] } } } } ] } ``` --- # Update connected calendar event Propose changing the title or time of an event the acting member organizes on a connected calendar. The member approves the change in Brigg. Supply both start and end when moving it; recurring events are unsupported. POST https://api.brigg.app/v1/operations/meetings.UpdateConnectedCalendarEvent ## Access & visibility Allow `meetings.UpdateConnectedCalendarEvent` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `event_id` | string | Yes | Brigg CalendarEvent record ID from ListCalendarEvents for this member's connected-provider event. It is not a Meeting ID or raw provider ID. The member must organize the event; recurring occurrences cannot be changed here. At least 1 character. At most 200 characters. | | `title` | string | No | Display title. At least 1 character. At most 500 characters. | | `start` | string | No | ISO 8601 start with an explicit time zone. For an update supply both start and end, or neither. | | `end` | string | No | ISO 8601 end with an explicit time zone, later than start. Updating only one boundary is refused. | ## Treat this as a proposal, not a completed calendar change API calls are non-interactive proposals, even with approved member delegation. A standing calendar permission does not bypass human approval here. A valid proposal normally returns awaiting_permission and posts a card to the acting member in Brigg. The member can approve or refuse it there; no public operation approves the card. For denied, stop: the member's calendar-action policy refuses the proposal. For done, inspect outcome.status. In particular, done with needs_auth means provider access must be connected or renewed; no calendar change happened. Open the returned auth_url only for that member to complete provider consent. The response schema also represents provider execution outcomes: only outcome.status=done denotes a completed attempt; failed includes reason. Replaying the same idempotency key returns the original proposal response, not live approval status. Do not poll by creating more proposals. After the member acts, check the connected calendar or its synchronized records in [List calendar events](/developers/reference/meetings/ListCalendarEvents); synchronization can lag. If provider consent changed and the member still wants the action, submit a deliberate new proposal with a new key. ## Provider access and action approval [List calendar connections](/developers/reference/meetings/ListCalendarConnections) first. The acting member needs a connected Google or Microsoft account with calendar write permission. The key's grant does not replace the provider's OAuth permission or the member's action policy. API calls propose an action for member approval; a standing setting does not turn an API call into the person's direct action. Inspect `status`, `outcome` and `permission` before treating the action as complete. A response requiring approval must be continued by the member in Brigg; returning an approval card is not evidence that a provider event was written. Retrying with a new idempotency key can create another logical action. For update or cancellation, use the Brigg record ID of the synchronized event, not a raw provider ID. A Brigg-owned event without a connected-provider identity uses the separate calendar-event operations. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `status` | string | Yes | Proposal state: awaiting_permission requires the member's decision in Brigg; denied means their policy refused it; done requires inspecting outcome.status and does not itself prove a calendar write. Allowed: `"done"`, `"awaiting_permission"`, `"denied"`. | | `outcome` | [object](#response-outcome) | No | Execution or provider-authorization result when top-level status is done. Missing on an awaiting_permission response. | | `card` | [CalendarApprovalCard](#calendarapprovalcard-response-card) | No | Approval card delivered to the acting member in Brigg. This is a proposal, not permission granted to the integration. | | `permission` | string | No | The refused action policy. Calendar proposals use create_calendar_event, including updates and cancellations. | ### response.outcome | Field | Type | Required | Description | | --- | --- | --- | --- | | `status` | string | Yes | done denotes a completed provider attempt; failed reports reason; needs_auth requires member provider consent before a new proposal can proceed. Allowed: `"done"`, `"failed"`, `"needs_auth"`. | | `reason` | string | No | Machine-readable cause, such as missing_scope, no_connection, rate_limited or provider_error. Treat the reason set as extensible; do not assume failed is safe to repeat blindly. | | `auth_url` | string | No | Member-only continuation URL when outcome.status=needs_auth. Open it for the same acting member to connect or renew provider access; do not fetch it with the API key. | | `job_id` | string | No | Optional shared action-result field. Calendar proposals do not return a polling job through this field; do not wait for it. | ### CalendarApprovalCard · response.card | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Identifier of the approval card. No public API accepts this ID to approve it or poll its decision. | | `kind` | string | Yes | Category identifying which variant of this model applies. Always `"card_agent_permission"`. | | `payload` | [object](#response-card-payload) | Yes | Action details shown for approval when the calendar policy requires review. | ### response.card.payload | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Category identifying which variant of this model applies. Always `"card_agent_permission"`. | | `permission` | string | Yes | create_calendar_event for this calendar action. Other values belong to the shared card schema. Allowed: `"create_calendar_event"`, `"send_email"`, `"email_people"`, `"text_people"`, `"place_calls"`, `"use_browser"`. | | `action` | [object (8 variants)](#response-card-payload-action) | Yes | The proposed calendar change. Only kind=update_calendar_event applies to this operation; other variants belong to the shared approval-card schema. | ### response.card.payload.action #### kind = "browser_task" | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Category identifying which variant of this model applies. Always `"browser_task"`. | | `goal` | string | Yes | Purpose the proposed agenda should help achieve. | | `start_url` | string | No | URL where the acting member begins the connection flow. | | `context` | string | No | Background information available for preparing the agenda. | | `attachments` | array of [object](#response-card-payload-action-variant1-attachments) | No | Attachments supplied for the related action. | | `keep_tab_open` | boolean | No | Whether the connection flow requires its browser tab to remain open. Allowed: `false`, `true`. | ### response.card.payload.action.variant1.attachments[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `file_id` | string | Yes | File identifier. | | `name` | string | Yes | Display name. | #### kind = "place_call" | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Category identifying which variant of this model applies. Always `"place_call"`. | | `to` | string | Yes | Recipients of the related message or calendar action. | | `name` | null or string | Yes | Display name. | | `brief` | string | Yes | Preparation summary for the upcoming meeting. | | `record_id` | string | No | Record identifier. | #### kind = "send_sms" | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Category identifying which variant of this model applies. Always `"send_sms"`. | | `to` | string | Yes | Recipients of the related message or calendar action. | | `name` | string | Yes | Display name. | | `text` | string | Yes | Text content. | | `record_id` | string | No | Record identifier. | | `unknown_recipient` | boolean | No | Whether the action includes a recipient not already recognized by the caller's policy. Allowed: `false`, `true`. | #### kind = "contact_person" | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Category identifying which variant of this model applies. Always `"contact_person"`. | | `to` | string | Yes | Recipients of the related message or calendar action. | | `subject` | string | Yes | Title or subject supplied for this calendar action. | | `body` | string | Yes | Descriptive content supplied for the calendar action. | | `instruction` | string | No | Instructions to use when preparing the requested meeting content. | #### kind = "send_email" | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Category identifying which variant of this model applies. Always `"send_email"`. | | `to` | array of string | Yes | Recipients of the related message or calendar action. | | `cc` | array of string | No | Recipients to copy on the related message. | | `subject` | string | Yes | Title or subject supplied for this calendar action. | | `body` | string | Yes | Descriptive content supplied for the calendar action. | #### kind = "create_calendar_event" | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Category identifying which variant of this model applies. Always `"create_calendar_event"`. | | `title` | string | Yes | Display title. | | `start` | string | Yes | Start of the interval. | | `end` | string | Yes | End of the interval; must be later than its start. | | `attendees` | array of string | No | People invited to the event and their invitation details. | | `add_conference` | boolean | No | Whether to request a video-conference link from the connected calendar provider. Allowed: `false`, `true`. | | `provider` | string | No | Connected calendar provider used for this action. Allowed: `"google"`, `"microsoft"`. | #### kind = "update_calendar_event" | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Category identifying which variant of this model applies. Always `"update_calendar_event"`. | | `event_id` | string | Yes | The same Brigg CalendarEvent record ID supplied as event_id. The card uses camelCase. | | `current` | [object](#response-card-payload-action-variant7-current) | Yes | Snapshot of the synchronized event when the proposal was prepared, not a promise that the event cannot change before approval. | | `title` | string | No | Display title. | | `start` | string | No | Start of the interval. | | `end` | string | No | End of the interval; must be later than its start. | ### response.card.payload.action.variant7.current | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string | Yes | Display title. | | `start` | string | Yes | Start of the interval. | | `end` | string | Yes | End of the interval; must be later than its start. | #### kind = "cancel_calendar_event" | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Category identifying which variant of this model applies. Always `"cancel_calendar_event"`. | | `event_id` | string | Yes | The same Brigg CalendarEvent record ID supplied as event_id. The card uses camelCase. | | `current` | [object](#response-card-payload-action-variant8-current) | Yes | Snapshot of the synchronized event when the proposal was prepared, not a promise that the event cannot change before approval. | ### response.card.payload.action.variant8.current | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string | Yes | Display title. | | `start` | string | Yes | Start of the interval. | | `end` | string | Yes | End of the interval; must be later than its start. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | | 400 | `event_not_found` | Choose the acting member's synchronized CalendarEvent ID, not a Meeting ID. | | 400 | `not_organizer` | Only the event's organizer can change it. Ask the organizer to act. | | 400 | `recurring_event` | Edit repeating events in the provider calendar; this API does not change occurrences or series. | | 400 | `invalid_range` | Use an end after start with explicit time zones. | | 400 | `invalid_action` | An update must change a title or supply both start and end. | ## Next steps - [List calendar connections](/developers/reference/meetings/ListCalendarConnections) - [List calendar events](/developers/reference/meetings/ListCalendarEvents) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Member approval is required HTTP 200 means the proposal was processed. No provider event has been changed yet. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.UpdateConnectedCalendarEvent' \ -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 '{ "event_id": "e_calendar_kickoff", "title": "Northstar planning review" }' ``` #### 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.UpdateConnectedCalendarEvent", { 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({ "event_id": "e_calendar_kickoff", "title": "Northstar planning review" }), }); 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 = { "event_id": "e_calendar_kickoff", "title": "Northstar planning review" } request = Request( "https://api.brigg.app/v1/operations/meetings.UpdateConnectedCalendarEvent", 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 { "status": "awaiting_permission", "card": { "id": "card_calendar_proposal", "kind": "card_agent_permission", "payload": { "kind": "card_agent_permission", "permission": "create_calendar_event", "action": { "kind": "update_calendar_event", "event_id": "e_calendar_kickoff", "current": { "title": "Northstar project kickoff", "start": "2026-11-10T09:00:00.000Z", "end": "2026-11-10T09:45:00.000Z" }, "title": "Northstar planning review" } } } } ``` ### The member's policy refuses the action Stop here. Broader key grants do not override the member's action policy. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.UpdateConnectedCalendarEvent' \ -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 '{ "event_id": "e_calendar_kickoff", "title": "Northstar planning review" }' ``` #### 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.UpdateConnectedCalendarEvent", { 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({ "event_id": "e_calendar_kickoff", "title": "Northstar planning review" }), }); 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 = { "event_id": "e_calendar_kickoff", "title": "Northstar planning review" } request = Request( "https://api.brigg.app/v1/operations/meetings.UpdateConnectedCalendarEvent", 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 { "status": "denied", "permission": "create_calendar_event" } ``` ### Provider consent needs attention This does not cancel or update the event. The acting member must complete the provider connection first. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.UpdateConnectedCalendarEvent' \ -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 '{ "event_id": "e_calendar_kickoff", "title": "Northstar planning review" }' ``` #### 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.UpdateConnectedCalendarEvent", { 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({ "event_id": "e_calendar_kickoff", "title": "Northstar planning review" }), }); 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 = { "event_id": "e_calendar_kickoff", "title": "Northstar planning review" } request = Request( "https://api.brigg.app/v1/operations/meetings.UpdateConnectedCalendarEvent", 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 { "status": "done", "outcome": { "status": "needs_auth", "reason": "missing_scope", "auth_url": "https://app.example.com/account" } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "event_id": { "type": "string", "minLength": 1, "maxLength": 200, "description": "Brigg CalendarEvent record ID from ListCalendarEvents for this member's connected-provider event. It is not a Meeting ID or raw provider ID. The member must organize the event; recurring occurrences cannot be changed here." }, "title": { "type": "string", "minLength": 1, "maxLength": 500, "description": "Display title." }, "start": { "type": "string", "description": "ISO 8601 start with an explicit time zone. For an update supply both start and end, or neither." }, "end": { "type": "string", "description": "ISO 8601 end with an explicit time zone, later than start. Updating only one boundary is refused." } }, "required": [ "event_id" ], "additionalProperties": false, "examples": [ { "event_id": "e_calendar_kickoff", "title": "Northstar planning review" } ] } ``` ```json-schema-response { "type": "object", "description": "done means the policy allowed an attempt: inspect outcome.status for the provider result. awaiting_permission means a person must approve the action in Brigg. denied means the member's policy refused it. An approval response is not a completed provider write.", "properties": { "status": { "type": "string", "enum": [ "done", "awaiting_permission", "denied" ], "description": "Proposal state: awaiting_permission requires the member's decision in Brigg; denied means their policy refused it; done requires inspecting outcome.status and does not itself prove a calendar write." }, "outcome": { "type": "object", "properties": { "status": { "type": "string", "enum": [ "done", "failed", "needs_auth" ], "description": "done denotes a completed provider attempt; failed reports reason; needs_auth requires member provider consent before a new proposal can proceed." }, "reason": { "type": "string", "description": "Machine-readable cause, such as missing_scope, no_connection, rate_limited or provider_error. Treat the reason set as extensible; do not assume failed is safe to repeat blindly." }, "auth_url": { "type": "string", "description": "Member-only continuation URL when outcome.status=needs_auth. Open it for the same acting member to connect or renew provider access; do not fetch it with the API key." }, "job_id": { "type": "string", "description": "Optional shared action-result field. Calendar proposals do not return a polling job through this field; do not wait for it." } }, "required": [ "status" ], "additionalProperties": false, "description": "Execution or provider-authorization result when top-level status is done. Missing on an awaiting_permission response." }, "card": { "description": "Approval card delivered to the acting member in Brigg. This is a proposal, not permission granted to the integration.", "title": "CalendarApprovalCard", "type": "object", "properties": { "id": { "type": "string", "description": "Identifier of the approval card. No public API accepts this ID to approve it or poll its decision." }, "kind": { "type": "string", "const": "card_agent_permission", "description": "Category identifying which variant of this model applies." }, "payload": { "type": "object", "properties": { "kind": { "type": "string", "const": "card_agent_permission", "description": "Category identifying which variant of this model applies." }, "permission": { "type": "string", "enum": [ "create_calendar_event", "send_email", "email_people", "text_people", "place_calls", "use_browser" ], "description": "create_calendar_event for this calendar action. Other values belong to the shared card schema." }, "action": { "anyOf": [ { "type": "object", "properties": { "kind": { "type": "string", "const": "browser_task", "description": "Category identifying which variant of this model applies." }, "goal": { "type": "string", "description": "Purpose the proposed agenda should help achieve." }, "start_url": { "type": "string", "description": "URL where the acting member begins the connection flow." }, "context": { "type": "string", "description": "Background information available for preparing the agenda." }, "attachments": { "type": "array", "items": { "type": "object", "properties": { "file_id": { "type": "string", "description": "File identifier." }, "name": { "type": "string", "description": "Display name." } }, "required": [ "file_id", "name" ], "additionalProperties": false }, "description": "Attachments supplied for the related action." }, "keep_tab_open": { "type": "boolean", "enum": [ false, true ], "description": "Whether the connection flow requires its browser tab to remain open." } }, "required": [ "kind", "goal" ], "additionalProperties": false, "description": "The proposed calendar change. Only kind=update_calendar_event applies to this operation; other variants belong to the shared approval-card schema." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "place_call", "description": "Category identifying which variant of this model applies." }, "to": { "type": "string", "description": "Recipients of the related message or calendar action." }, "name": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Display name." }, "brief": { "type": "string", "description": "Preparation summary for the upcoming meeting." }, "record_id": { "type": "string", "description": "Record identifier." } }, "required": [ "kind", "to", "name", "brief" ], "additionalProperties": false, "description": "The proposed calendar change. Only kind=update_calendar_event applies to this operation; other variants belong to the shared approval-card schema." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "send_sms", "description": "Category identifying which variant of this model applies." }, "to": { "type": "string", "description": "Recipients of the related message or calendar action." }, "name": { "type": "string", "description": "Display name." }, "text": { "type": "string", "description": "Text content." }, "record_id": { "type": "string", "description": "Record identifier." }, "unknown_recipient": { "type": "boolean", "enum": [ false, true ], "description": "Whether the action includes a recipient not already recognized by the caller's policy." } }, "required": [ "kind", "to", "name", "text" ], "additionalProperties": false, "description": "The proposed calendar change. Only kind=update_calendar_event applies to this operation; other variants belong to the shared approval-card schema." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "contact_person", "description": "Category identifying which variant of this model applies." }, "to": { "type": "string", "description": "Recipients of the related message or calendar action." }, "subject": { "type": "string", "description": "Title or subject supplied for this calendar action." }, "body": { "type": "string", "description": "Descriptive content supplied for the calendar action." }, "instruction": { "type": "string", "description": "Instructions to use when preparing the requested meeting content." } }, "required": [ "kind", "to", "subject", "body" ], "additionalProperties": false, "description": "The proposed calendar change. Only kind=update_calendar_event applies to this operation; other variants belong to the shared approval-card schema." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "send_email", "description": "Category identifying which variant of this model applies." }, "to": { "type": "array", "items": { "type": "string" }, "description": "Recipients of the related message or calendar action." }, "cc": { "type": "array", "items": { "type": "string" }, "description": "Recipients to copy on the related message." }, "subject": { "type": "string", "description": "Title or subject supplied for this calendar action." }, "body": { "type": "string", "description": "Descriptive content supplied for the calendar action." } }, "required": [ "kind", "to", "subject", "body" ], "additionalProperties": false, "description": "The proposed calendar change. Only kind=update_calendar_event applies to this operation; other variants belong to the shared approval-card schema." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "create_calendar_event", "description": "Category identifying which variant of this model applies." }, "title": { "type": "string", "description": "Display title." }, "start": { "type": "string", "description": "Start of the interval." }, "end": { "type": "string", "description": "End of the interval; must be later than its start." }, "attendees": { "type": "array", "items": { "type": "string" }, "description": "People invited to the event and their invitation details." }, "add_conference": { "type": "boolean", "enum": [ false, true ], "description": "Whether to request a video-conference link from the connected calendar provider." }, "provider": { "type": "string", "enum": [ "google", "microsoft" ], "description": "Connected calendar provider used for this action." } }, "required": [ "kind", "title", "start", "end" ], "additionalProperties": false, "description": "The proposed calendar change. Only kind=update_calendar_event applies to this operation; other variants belong to the shared approval-card schema." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "update_calendar_event", "description": "Category identifying which variant of this model applies." }, "event_id": { "type": "string", "description": "The same Brigg CalendarEvent record ID supplied as event_id. The card uses camelCase." }, "current": { "type": "object", "properties": { "title": { "type": "string", "description": "Display title." }, "start": { "type": "string", "description": "Start of the interval." }, "end": { "type": "string", "description": "End of the interval; must be later than its start." } }, "required": [ "title", "start", "end" ], "additionalProperties": false, "description": "Snapshot of the synchronized event when the proposal was prepared, not a promise that the event cannot change before approval." }, "title": { "type": "string", "description": "Display title." }, "start": { "type": "string", "description": "Start of the interval." }, "end": { "type": "string", "description": "End of the interval; must be later than its start." } }, "required": [ "kind", "event_id", "current" ], "additionalProperties": false, "description": "The proposed calendar change. Only kind=update_calendar_event applies to this operation; other variants belong to the shared approval-card schema." }, { "type": "object", "properties": { "kind": { "type": "string", "const": "cancel_calendar_event", "description": "Category identifying which variant of this model applies." }, "event_id": { "type": "string", "description": "The same Brigg CalendarEvent record ID supplied as event_id. The card uses camelCase." }, "current": { "type": "object", "properties": { "title": { "type": "string", "description": "Display title." }, "start": { "type": "string", "description": "Start of the interval." }, "end": { "type": "string", "description": "End of the interval; must be later than its start." } }, "required": [ "title", "start", "end" ], "additionalProperties": false, "description": "Snapshot of the synchronized event when the proposal was prepared, not a promise that the event cannot change before approval." } }, "required": [ "kind", "event_id", "current" ], "additionalProperties": false, "description": "The proposed calendar change. Only kind=update_calendar_event applies to this operation; other variants belong to the shared approval-card schema." } ], "description": "The proposed calendar change. Only kind=update_calendar_event applies to this operation; other variants belong to the shared approval-card schema." } }, "required": [ "kind", "permission", "action" ], "additionalProperties": false, "description": "Action details shown for approval when the calendar policy requires review." } }, "required": [ "id", "kind", "payload" ], "additionalProperties": false }, "permission": { "type": "string", "description": "The refused action policy. Calendar proposals use create_calendar_event, including updates and cancellations." } }, "required": [ "status" ], "additionalProperties": false, "examples": [ { "status": "awaiting_permission", "card": { "id": "card_calendar_proposal", "kind": "card_agent_permission", "payload": { "kind": "card_agent_permission", "permission": "create_calendar_event", "action": { "kind": "update_calendar_event", "event_id": "e_calendar_kickoff", "current": { "title": "Northstar project kickoff", "start": "2026-11-10T09:00:00.000Z", "end": "2026-11-10T09:45:00.000Z" }, "title": "Northstar planning review" } } } } ] } ``` --- # Prepare meeting Prepare a meeting from a connected calendar event, including participant records, a brief and an agenda. Repeated requests reuse the same prepared meeting. POST https://api.brigg.app/v1/operations/meetings.PrepareMeeting ## Access & visibility Allow `meetings.PrepareMeeting` on your API key. Resource write permissions: `core:Meeting`, `core:Company`, `core:Person`. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `event_id` | string | Yes | ID of a synchronized CalendarEvent visible to the acting member. Find it with ListCalendarEvents. Use its Brigg record id, not the provider's event ID or a Meeting ID. At least 1 character. | ## From calendar event to prepared meeting Find the event with [List calendar events](/developers/reference/meetings/ListCalendarEvents) under the same acting member. Connected events must have synchronized into Brigg first; this call does not connect an account or create a provider event. Preparation creates or reuses a companion Meeting, links attendee contacts and companies, and starts background preparation and enrichment. It can therefore create customer records as well as a meeting. Existing contacts and companies are reused where matched. The credential’s grants and the selected member’s private and project data boundaries apply, along with the meeting-sharing settings. A 200 response means the meeting identity is available. Briefs, agenda and enrichment can still be pending or fail independently, for example when background AI work cannot start. Read [Get meeting](/developers/reference/meetings/GetMeeting) for the published agenda, participants and linked records; inspect detailed preparation progress in Brigg. The public Meeting model does not expose a preparation-status field or the preparation brief. Its status is the meeting lifecycle, not preparation progress. Retries reuse the companion rather than creating another meeting. Keep the same idempotency key for a lost response. A later deliberate preparation attempt is a new logical action and needs a new key; repeating the call is not a way to force regeneration of completed preparation. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `meeting_id` | string | Yes | ID of the companion Meeting record, which may already have existed. Read it with meetings.GetMeeting using the same member identity. This is not a preparation job ID or a signal that generated content is ready. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | | 404 | `calendar_event_not_found` | The synchronized event is missing or not visible to this acting member. Discover it with ListCalendarEvents under the same identity. | ## Next steps - [List calendar events](/developers/reference/meetings/ListCalendarEvents) - [Get meeting](/developers/reference/meetings/GetMeeting) - [List calendar connections](/developers/reference/meetings/ListCalendarConnections) - [List people](/developers/reference/customers/ListPeople) - [List companies](/developers/reference/customers/ListCompanies) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Prepare a synchronized event Use a calendar event returned for this acting member. The returned meeting_id is a separate record identity. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/meetings.PrepareMeeting' \ -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 '{ "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.PrepareMeeting", { 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({ "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 = { "event_id": "e_calendar_kickoff" } request = Request( "https://api.brigg.app/v1/operations/meetings.PrepareMeeting", 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 { "meeting_id": "e_meeting_kickoff" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "event_id": { "type": "string", "minLength": 1, "description": "ID of a synchronized CalendarEvent visible to the acting member. Find it with ListCalendarEvents. Use its Brigg record id, not the provider's event ID or a Meeting ID." } }, "required": [ "event_id" ], "additionalProperties": false, "examples": [ { "event_id": "e_calendar_kickoff" } ] } ``` ```json-schema-response { "type": "object", "properties": { "meeting_id": { "type": "string", "description": "ID of the companion Meeting record, which may already have existed. Read it with meetings.GetMeeting using the same member identity. This is not a preparation job ID or a signal that generated content is ready." } }, "required": [ "meeting_id" ], "additionalProperties": false, "examples": [ { "meeting_id": "e_meeting_kickoff" } ] } ``` --- # Get newsletter issue Read an issue’s preparation and delivery state. Generating is still in progress; ready means the draft is prepared. A manual issue needs a person to review and send it through review_url. Failed issues keep their record so they can be inspected. POST https://api.brigg.app/v1/operations/newsletters.GetNewsletterIssue ## Access & visibility Allow `newsletters.GetNewsletterIssue` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `issue_id` | string | Yes | Use issue_id from the selected schedule's issues. It differs from the underlying newsletter_id. [newsletters.ListNewsletterIssues](/developers/reference/newsletters/ListNewsletterIssues). At least 1 character. | ## Preparation, review and sending are separate A schedule produces issues. An issue has its own `issue_id`; its generated content has a separate `newsletter_id`. Read [Get newsletter issue](/developers/reference/newsletters/GetNewsletterIssue) until that content and its `review_url` are available. A schedule start or run response does not mean preparation has finished. Public callers use manual approval. A person reviews and sends the issue in Brigg; preparing content or saving a draft does not send it to the audience. [Send newsletter test email](/developers/reference/newsletters/SendNewsletterTestEmail) sends a test to the acting member, not the subscriber list. A schedule's `start_at` is Unix milliseconds and its `timezone` is an IANA zone used for recurrence. `run_now` creates an extra first issue without consuming the first scheduled slot. Pause a schedule with `paused: true` when you want to stop future preparation while retaining the schedule. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `issue_id` | string | Yes | Issue identifier. | | `schedule_id` | string | Yes | Schedule identifier. | | `newsletter_id` | string | Yes | Newsletter identifier. | | `number` | integer | Yes | Issue number within this newsletter series. | | `status` | string | Yes | Current state reported for this item. Treat values as extensible unless an enum is declared. Allowed: `"generating"`, `"ready"`, `"sent"`, `"failed"`. | | `scheduled_for` | integer | Yes | Time the issue was scheduled for preparation, in Unix milliseconds. | | `review_url` | string | Yes | Brigg URL for reviewing this newsletter; it does not send the issue. Format: uri. | | `next_action` | string or null | Yes | Next step needed for this issue. Manual issues must be reviewed and sent in Brigg. Allowed: `"review_and_send"`, `"review_failure"`, `null`. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [List newsletter schedules](/developers/reference/newsletters/ListNewsletterSchedules) - [List newsletter issues](/developers/reference/newsletters/ListNewsletterIssues) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/newsletters.GetNewsletterIssue' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "issue_id": "e_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/newsletters.GetNewsletterIssue", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "issue_id": "e_example" }), }); 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 payload = { "issue_id": "e_example" } request = Request( "https://api.brigg.app/v1/operations/newsletters.GetNewsletterIssue", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "issue_id": "e_example", "schedule_id": "e_example", "newsletter_id": "e_example", "number": 1, "status": "generating", "scheduled_for": 1, "review_url": "https://brigg.app/settings", "next_action": "review_and_send" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "issue_id": { "type": "string", "minLength": 1, "description": "Use issue_id from the selected schedule's issues. It differs from the underlying newsletter_id. [newsletters.ListNewsletterIssues](/developers/reference/newsletters/ListNewsletterIssues)." } }, "required": [ "issue_id" ], "additionalProperties": false, "examples": [ { "issue_id": "e_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "issue_id": { "type": "string", "description": "Issue identifier." }, "schedule_id": { "type": "string", "description": "Schedule identifier." }, "newsletter_id": { "type": "string", "description": "Newsletter identifier." }, "number": { "type": "integer", "description": "Issue number within this newsletter series." }, "status": { "type": "string", "enum": [ "generating", "ready", "sent", "failed" ], "description": "Current state reported for this item. Treat values as extensible unless an enum is declared." }, "scheduled_for": { "type": "integer", "description": "Time the issue was scheduled for preparation, in Unix milliseconds." }, "review_url": { "type": "string", "format": "uri", "description": "Brigg URL for reviewing this newsletter; it does not send the issue." }, "next_action": { "type": [ "string", "null" ], "enum": [ "review_and_send", "review_failure", null ], "description": "Next step needed for this issue. Manual issues must be reviewed and sent in Brigg." } }, "required": [ "issue_id", "schedule_id", "newsletter_id", "number", "status", "scheduled_for", "review_url", "next_action" ], "additionalProperties": false, "examples": [ { "issue_id": "e_example", "schedule_id": "e_example", "newsletter_id": "e_example", "number": 1, "status": "generating", "scheduled_for": 1, "review_url": "https://brigg.app/settings", "next_action": "review_and_send" } ] } ``` --- # List newsletter issues List a schedule’s generated issues with their newsletter IDs, state and review links. Use the issue ID for status checks and deletion. POST https://api.brigg.app/v1/operations/newsletters.ListNewsletterIssues ## Access & visibility Allow `newsletters.ListNewsletterIssues` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `schedule_id` | string | Yes | Use schedule_id from the schedule listing. A schedule can produce multiple issues. [newsletters.ListNewsletterSchedules](/developers/reference/newsletters/ListNewsletterSchedules). At least 1 character. | ## Preparation, review and sending are separate A schedule produces issues. An issue has its own `issue_id`; its generated content has a separate `newsletter_id`. Read [Get newsletter issue](/developers/reference/newsletters/GetNewsletterIssue) until that content and its `review_url` are available. A schedule start or run response does not mean preparation has finished. Public callers use manual approval. A person reviews and sends the issue in Brigg; preparing content or saving a draft does not send it to the audience. [Send newsletter test email](/developers/reference/newsletters/SendNewsletterTestEmail) sends a test to the acting member, not the subscriber list. A schedule's `start_at` is Unix milliseconds and its `timezone` is an IANA zone used for recurrence. `run_now` creates an extra first issue without consuming the first scheduled slot. Pause a schedule with `paused: true` when you want to stop future preparation while retaining the schedule. ## Response Returns **200 OK** with a JSON body. This operation has no continuation cursor. An empty `items` array means no matching visible results were returned. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [Newsletter issue](#newsletter-issue-response-items) | Yes | Issues belonging to the selected newsletter schedule. This operation has no cursor pagination. | ### Newsletter issue · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `issue_id` | string | Yes | Issue ID used to read or review this issue. | | `schedule_id` | string | Yes | Schedule that generated this issue. | | `newsletter_id` | string | Yes | Newsletter content ID associated with this issue. | | `number` | integer | Yes | Issue sequence number within the schedule. | | `status` | string | Yes | generating means content is being prepared; ready awaits review; sent has been sent; failed needs attention. Allowed: `"generating"`, `"ready"`, `"sent"`, `"failed"`. | | `scheduled_for` | integer | Yes | Scheduled issue time in Unix milliseconds; this is not confirmation that email was sent. | | `review_url` | string | Yes | Open this issue in Brigg to review its content and explicitly send it. Format: uri. | | `next_action` | string or null | Yes | review_and_send requests a person's review; review_failure requests investigation; null means neither action is currently requested. Allowed: `"review_and_send"`, `"review_failure"`, `null`. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [List newsletter schedules](/developers/reference/newsletters/ListNewsletterSchedules) - [Get newsletter issue](/developers/reference/newsletters/GetNewsletterIssue) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/newsletters.ListNewsletterIssues' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "schedule_id": "e_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/newsletters.ListNewsletterIssues", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "schedule_id": "e_example" }), }); 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 payload = { "schedule_id": "e_example" } request = Request( "https://api.brigg.app/v1/operations/newsletters.ListNewsletterIssues", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "issue_id": "issue_november", "schedule_id": "schedule_customer_updates", "newsletter_id": "newsletter_updates", "number": 3, "status": "ready", "scheduled_for": 1794301200000, "review_url": "https://example.com/newsletters/issue_november", "next_action": "review_and_send" } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "schedule_id": { "type": "string", "minLength": 1, "description": "Use schedule_id from the schedule listing. A schedule can produce multiple issues. [newsletters.ListNewsletterSchedules](/developers/reference/newsletters/ListNewsletterSchedules)." } }, "required": [ "schedule_id" ], "additionalProperties": false, "examples": [ { "schedule_id": "e_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "issue_id": { "type": "string", "description": "Issue ID used to read or review this issue.", "examples": [ "issue_november" ] }, "schedule_id": { "type": "string", "description": "Schedule that generated this issue.", "examples": [ "schedule_customer_updates" ] }, "newsletter_id": { "type": "string", "description": "Newsletter content ID associated with this issue.", "examples": [ "newsletter_updates" ] }, "number": { "type": "integer", "description": "Issue sequence number within the schedule.", "examples": [ 3 ] }, "status": { "type": "string", "enum": [ "generating", "ready", "sent", "failed" ], "description": "generating means content is being prepared; ready awaits review; sent has been sent; failed needs attention.", "examples": [ "ready" ] }, "scheduled_for": { "type": "integer", "description": "Scheduled issue time in Unix milliseconds; this is not confirmation that email was sent.", "examples": [ 1794301200000 ] }, "review_url": { "type": "string", "format": "uri", "description": "Open this issue in Brigg to review its content and explicitly send it.", "examples": [ "https://example.com/newsletters/issue_november" ] }, "next_action": { "type": [ "string", "null" ], "enum": [ "review_and_send", "review_failure", null ], "description": "review_and_send requests a person's review; review_failure requests investigation; null means neither action is currently requested.", "examples": [ "review_and_send" ] } }, "required": [ "issue_id", "schedule_id", "newsletter_id", "number", "status", "scheduled_for", "review_url", "next_action" ], "additionalProperties": false, "title": "Newsletter issue" }, "description": "Issues belonging to the selected newsletter schedule. This operation has no cursor pagination." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "issue_id": "issue_november", "schedule_id": "schedule_customer_updates", "newsletter_id": "newsletter_updates", "number": 3, "status": "ready", "scheduled_for": 1794301200000, "review_url": "https://example.com/newsletters/issue_november", "next_action": "review_and_send" } ] } ] } ``` --- # Delete newsletter issue Delete a scheduled newsletter's issue record after its document has been deleted. An issue that is still being written cannot be deleted. POST https://api.brigg.app/v1/operations/newsletters.DeleteNewsletterIssue ## Access & visibility Allow `newsletters.DeleteNewsletterIssue` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `issue_id` | string | Yes | Use issue_id from the selected schedule's issues. It differs from the underlying newsletter_id. [newsletters.ListNewsletterIssues](/developers/reference/newsletters/ListNewsletterIssues). At least 1 character. | ## Preparation, review and sending are separate A schedule produces issues. An issue has its own `issue_id`; its generated content has a separate `newsletter_id`. Read [Get newsletter issue](/developers/reference/newsletters/GetNewsletterIssue) until that content and its `review_url` are available. A schedule start or run response does not mean preparation has finished. Public callers use manual approval. A person reviews and sends the issue in Brigg; preparing content or saving a draft does not send it to the audience. [Send newsletter test email](/developers/reference/newsletters/SendNewsletterTestEmail) sends a test to the acting member, not the subscriber list. A schedule's `start_at` is Unix milliseconds and its `timezone` is an IANA zone used for recurrence. `run_now` creates an extra first issue without consuming the first scheduled slot. Pause a schedule with `paused: true` when you want to stop future preparation while retaining the schedule. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | ## Next steps - [List newsletter schedules](/developers/reference/newsletters/ListNewsletterSchedules) - [List newsletter issues](/developers/reference/newsletters/ListNewsletterIssues) - [Get newsletter issue](/developers/reference/newsletters/GetNewsletterIssue) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/newsletters.DeleteNewsletterIssue' \ -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 '{ "issue_id": "e_example" }' ``` #### 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/newsletters.DeleteNewsletterIssue", { 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({ "issue_id": "e_example" }), }); 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 = { "issue_id": "e_example" } request = Request( "https://api.brigg.app/v1/operations/newsletters.DeleteNewsletterIssue", 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 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "issue_id": { "type": "string", "minLength": 1, "description": "Use issue_id from the selected schedule's issues. It differs from the underlying newsletter_id. [newsletters.ListNewsletterIssues](/developers/reference/newsletters/ListNewsletterIssues)." } }, "required": [ "issue_id" ], "additionalProperties": false, "examples": [ { "issue_id": "e_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." } }, "required": [ "ok" ], "additionalProperties": false, "examples": [ { "ok": true } ] } ``` --- # Save newsletter draft Save a newsletter's subject, preview text, audience and sender so preparation can resume later. POST https://api.brigg.app/v1/operations/newsletters.SaveNewsletterDraft ## Access & visibility Allow `newsletters.SaveNewsletterDraft` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `newsletter_id` | string | Yes | Read the issue and use its newsletter_id when available. This is the content identity, not the issue or schedule ID. [newsletters.GetNewsletterIssue](/developers/reference/newsletters/GetNewsletterIssue). At least 1 character. | | `subject` | string or null | No | Subject line shown to recipients. | | `preview_text` | string or null | No | The inbox preheader. | | `audience` | [object](#request-audience) or null | No | Selected recipients or audience definition for this newsletter. | ### request.audience | Field | Type | Required | Description | | --- | --- | --- | --- | | `mode` | string | Yes | all selects all contacts; tags selects contacts carrying at least one selected tag; manual uses only the supplied email addresses. Allowed: `"all"`, `"tags"`, `"manual"`. | | `tags` | array of string | Yes | Stable contact tag keys. Used only in tags mode. | | `extra` | array of string | Yes | Explicit additional email addresses. In manual mode these are the entire audience. | ## Preparation, review and sending are separate A schedule produces issues. An issue has its own `issue_id`; its generated content has a separate `newsletter_id`. Read [Get newsletter issue](/developers/reference/newsletters/GetNewsletterIssue) until that content and its `review_url` are available. A schedule start or run response does not mean preparation has finished. Public callers use manual approval. A person reviews and sends the issue in Brigg; preparing content or saving a draft does not send it to the audience. [Send newsletter test email](/developers/reference/newsletters/SendNewsletterTestEmail) sends a test to the acting member, not the subscriber list. A schedule's `start_at` is Unix milliseconds and its `timezone` is an IANA zone used for recurrence. `run_now` creates an extra first issue without consuming the first scheduled slot. Pause a schedule with `paused: true` when you want to stop future preparation while retaining the schedule. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | ## Next steps - [List newsletter schedules](/developers/reference/newsletters/ListNewsletterSchedules) - [List newsletter issues](/developers/reference/newsletters/ListNewsletterIssues) - [Get newsletter issue](/developers/reference/newsletters/GetNewsletterIssue) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/newsletters.SaveNewsletterDraft' \ -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 '{ "newsletter_id": "e_example" }' ``` #### 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/newsletters.SaveNewsletterDraft", { 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({ "newsletter_id": "e_example" }), }); 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 = { "newsletter_id": "e_example" } request = Request( "https://api.brigg.app/v1/operations/newsletters.SaveNewsletterDraft", 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 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "newsletter_id": { "type": "string", "minLength": 1, "description": "Read the issue and use its newsletter_id when available. This is the content identity, not the issue or schedule ID. [newsletters.GetNewsletterIssue](/developers/reference/newsletters/GetNewsletterIssue)." }, "subject": { "anyOf": [ { "type": "string", "maxLength": 500 }, { "type": "null" } ], "description": "Subject line shown to recipients." }, "preview_text": { "anyOf": [ { "type": "string", "maxLength": 500 }, { "type": "null" } ], "description": "The inbox preheader." }, "audience": { "anyOf": [ { "type": "object", "properties": { "mode": { "type": "string", "enum": [ "all", "tags", "manual" ], "description": "all selects all contacts; tags selects contacts carrying at least one selected tag; manual uses only the supplied email addresses." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable contact tag keys. Used only in tags mode." }, "extra": { "type": "array", "items": { "type": "string", "pattern": "^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$" }, "description": "Explicit additional email addresses. In manual mode these are the entire audience." } }, "required": [ "mode", "tags", "extra" ], "additionalProperties": false, "$schema": "http://json-schema.org/draft-07/schema#" }, { "type": "null" } ], "description": "Selected recipients or audience definition for this newsletter." } }, "required": [ "newsletter_id" ], "additionalProperties": false, "examples": [ { "newsletter_id": "e_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." } }, "required": [ "ok" ], "additionalProperties": false, "examples": [ { "ok": true } ] } ``` --- # Send newsletter test email Send a newsletter preview to your own email address, with its normal layout, merge fields and unsubscribe footer. Does not send to the selected audience or publish the newsletter. POST https://api.brigg.app/v1/operations/newsletters.SendNewsletterTestEmail ## Access & visibility Allow `newsletters.SendNewsletterTestEmail` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `newsletter_id` | string | Yes | Read the issue and use its newsletter_id when available. This is the content identity, not the issue or schedule ID. [newsletters.GetNewsletterIssue](/developers/reference/newsletters/GetNewsletterIssue). At least 1 character. | | `subject` | string or null | No | Subject override for this test only, trimmed before use. Omit, null or blank uses the saved campaign subject, then a subject derived from the content. It does not update the saved draft. | | `preview_text` | string or null | No | Inbox preview line for this test only. Omit or null uses the saved draft's preview text; an empty string explicitly removes it from this test. It does not update the saved draft. | ## Send a preview without changing the campaign Read [Get newsletter issue](/developers/reference/newsletters/GetNewsletterIssue) and retain its newsletter_id once prepared. The test uses the acting member's current draft when present, otherwise the published content. The member must be allowed to act on this newsletter, not merely know its ID. The test is addressed only to the acting member, personalizes merge fields with that member's contact details, and prefixes the subject with a preview label in the newsletter's language. It does not save your overrides, publish the newsletter, create a campaign send or mail subscribers. A successful response means accepted for sending, not delivered. Inspect the actual email's layout, links, merge values and footer before a person sends the campaign in Brigg. The test recipient's existing unsubscribe preference still applies. After a lost response, retry with the original idempotency key instead of creating another preview. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | True when the test message was accepted for sending. It does not confirm mailbox delivery or that a person read it. | | `message_id` | string | Yes | Identifier for this outgoing test message. Keep it for troubleshooting. It is not a newsletter, issue or Brigg inbox-message ID; this operation provides no delivery-status polling endpoint. | | `to` | string | Yes | Email address belonging to the approved acting member. There is no recipient override; member delegation selects whose own preview is sent. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | | 400 | `no_email` | The acting member has no email address for the preview. Complete that member's account setup in Brigg. | | 409 | `not_built` | The selected newsletter has no prepared email content. Finish preparing and reviewing it in Brigg first. | | 409 | `images_not_hosted` | Newsletter images are not ready for email delivery. Finish preparing the newsletter's images in Brigg before retrying. | | 422 | `suppressed` | This member's email address is suppressed or unsubscribed for this workspace. No preview was sent; respect the existing preference. | ## Next steps - [Get newsletter issue](/developers/reference/newsletters/GetNewsletterIssue) - [Save newsletter draft](/developers/reference/newsletters/SaveNewsletterDraft) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Preview the saved draft The preview goes to Jamie, the approved acting member. No subscriber receives it. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/newsletters.SendNewsletterTestEmail' \ -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 '{ "newsletter_id": "c_newsletter_autumn" }' ``` #### 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/newsletters.SendNewsletterTestEmail", { 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({ "newsletter_id": "c_newsletter_autumn" }), }); 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 = { "newsletter_id": "c_newsletter_autumn" } request = Request( "https://api.brigg.app/v1/operations/newsletters.SendNewsletterTestEmail", 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, "message_id": "msg_preview_autumn", "to": "jamie@example.com" } ``` ### Test a subject with no preheader These overrides affect this message only. Empty preview_text clears the inbox preview line. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/newsletters.SendNewsletterTestEmail' \ -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 '{ "newsletter_id": "c_newsletter_autumn", "subject": "Your autumn project update", "preview_text": "" }' ``` #### 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/newsletters.SendNewsletterTestEmail", { 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({ "newsletter_id": "c_newsletter_autumn", "subject": "Your autumn project update", "preview_text": "" }), }); 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 = { "newsletter_id": "c_newsletter_autumn", "subject": "Your autumn project update", "preview_text": "" } request = Request( "https://api.brigg.app/v1/operations/newsletters.SendNewsletterTestEmail", 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, "message_id": "msg_preview_autumn", "to": "jamie@example.com" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "newsletter_id": { "type": "string", "minLength": 1, "description": "Read the issue and use its newsletter_id when available. This is the content identity, not the issue or schedule ID. [newsletters.GetNewsletterIssue](/developers/reference/newsletters/GetNewsletterIssue)." }, "subject": { "type": [ "string", "null" ], "description": "Subject override for this test only, trimmed before use. Omit, null or blank uses the saved campaign subject, then a subject derived from the content. It does not update the saved draft." }, "preview_text": { "type": [ "string", "null" ], "description": "Inbox preview line for this test only. Omit or null uses the saved draft's preview text; an empty string explicitly removes it from this test. It does not update the saved draft." } }, "required": [ "newsletter_id" ], "additionalProperties": false, "examples": [ { "newsletter_id": "c_newsletter_autumn" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "True when the test message was accepted for sending. It does not confirm mailbox delivery or that a person read it." }, "message_id": { "type": "string", "description": "Identifier for this outgoing test message. Keep it for troubleshooting. It is not a newsletter, issue or Brigg inbox-message ID; this operation provides no delivery-status polling endpoint." }, "to": { "type": "string", "description": "Email address belonging to the approved acting member. There is no recipient override; member delegation selects whose own preview is sent." } }, "required": [ "ok", "message_id", "to" ], "additionalProperties": false, "examples": [ { "ok": true, "message_id": "msg_preview_autumn", "to": "jamie@example.com" } ] } ``` --- # Get newsletter settings Read the workspace's saved newsletter sender name and reply address, together with suggested defaults. POST https://api.brigg.app/v1/operations/newsletters.GetNewsletterSettings ## Access & visibility Allow `newsletters.GetNewsletterSettings` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/permissions) ## Request No parameters. Send an empty JSON object (`{}`). ## Saved settings and suggestions are different These are workspace sender settings. Both reading and changing them require an approved owner or administrator. sender_name and reply_to are the saved overrides; null means no override is saved. default_sender_name is the workspace name used when the sender override is absent. suggested_reply_to is the acting member’s own email address when available. It is a form suggestion, not an automatically saved setting or proof of the effective Reply-To. To use it for future newsletters, explicitly save it with [Update newsletter settings](/developers/reference/newsletters/UpdateNewsletterSettings). An unset saved Reply-To uses Brigg’s workspace-mailbox fallback at send time. These settings do not choose recipients, send a newsletter or change the authenticated sending domain. Send a test email to inspect the actual From and Reply-To before sending a campaign. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `sender_name` | string or null | Yes | Saved sender display-name override, or null to use default_sender_name. | | `reply_to` | string or null | Yes | Saved Reply-To override, or null when unset. The suggested_reply_to value is not automatically applied. | | `default_sender_name` | string | Yes | Customer-facing workspace name used when no sender-name override is saved. | | `suggested_reply_to` | string or null | Yes | Acting member’s own email address, or null if none is available. A suggestion for an administrator to save, not the effective send-time address. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [Update newsletter settings](/developers/reference/newsletters/UpdateNewsletterSettings) - [Send newsletter test email](/developers/reference/newsletters/SendNewsletterTestEmail) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Read settings before saving an override Jamie’s address is suggested but not yet saved. The workspace name remains the default. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/newsletters.GetNewsletterSettings' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{}' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/newsletters.GetNewsletterSettings", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/newsletters.GetNewsletterSettings", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "sender_name": null, "reply_to": null, "default_sender_name": "Northstar Consulting", "suggested_reply_to": "jamie@example.com" } ``` ### Read configured sender settings The saved team address applies instead of Jamie’s suggested personal address. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/newsletters.GetNewsletterSettings' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{}' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/newsletters.GetNewsletterSettings", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/newsletters.GetNewsletterSettings", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "sender_name": "Northstar team", "reply_to": "team@example.com", "default_sender_name": "Northstar Consulting", "suggested_reply_to": "jamie@example.com" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": {}, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "sender_name": { "type": [ "string", "null" ], "description": "Saved sender display-name override, or null to use default_sender_name." }, "reply_to": { "type": [ "string", "null" ], "description": "Saved Reply-To override, or null when unset. The suggested_reply_to value is not automatically applied." }, "default_sender_name": { "type": "string", "description": "Customer-facing workspace name used when no sender-name override is saved." }, "suggested_reply_to": { "type": [ "string", "null" ], "description": "Acting member’s own email address, or null if none is available. A suggestion for an administrator to save, not the effective send-time address." } }, "required": [ "sender_name", "reply_to", "default_sender_name", "suggested_reply_to" ], "additionalProperties": false, "examples": [ { "sender_name": null, "reply_to": null, "default_sender_name": "Northstar Consulting", "suggested_reply_to": "jamie@example.com" } ] } ``` --- # Update newsletter settings Update the workspace's default newsletter sender name and reply email address. POST https://api.brigg.app/v1/operations/newsletters.UpdateNewsletterSettings ## Access & visibility Allow `newsletters.UpdateNewsletterSettings` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `sender_name` | string or null | No | New sender display-name override. Omit to preserve it; null or blank clears it to the workspace default. Quotes, backslashes and line breaks are removed; the saved name is trimmed to 78 characters. | | `reply_to` | string or null | No | Single valid reply email address. Omit to preserve it; null or blank clears the saved override. This does not change the authenticated sending domain. | ## Saved settings and suggestions are different These are workspace sender settings. Both reading and changing them require an approved owner or administrator. sender_name and reply_to are the saved overrides; null means no override is saved. default_sender_name is the workspace name used when the sender override is absent. suggested_reply_to is the acting member’s own email address when available. It is a form suggestion, not an automatically saved setting or proof of the effective Reply-To. To use it for future newsletters, explicitly save it with [Update newsletter settings](/developers/reference/newsletters/UpdateNewsletterSettings). An unset saved Reply-To uses Brigg’s workspace-mailbox fallback at send time. These settings do not choose recipients, send a newsletter or change the authenticated sending domain. Send a test email to inspect the actual From and Reply-To before sending a campaign. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | The settings were saved. Read GetNewsletterSettings for the resulting values; no email has been sent. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 400 | `invalid_reply_to` | Supply a single valid email address, or null to clear the override. | ## Next steps - [Get newsletter settings](/developers/reference/newsletters/GetNewsletterSettings) - [Send newsletter test email](/developers/reference/newsletters/SendNewsletterTestEmail) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Save a team sender Only these settings change; no campaign is sent. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/newsletters.UpdateNewsletterSettings' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "sender_name": "Northstar team", "reply_to": "team@example.com" }' ``` #### TypeScript ```typescript 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/newsletters.UpdateNewsletterSettings", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "sender_name": "Northstar team", "reply_to": "team@example.com" }), }); 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 = { "sender_name": "Northstar team", "reply_to": "team@example.com" } request = Request( "https://api.brigg.app/v1/operations/newsletters.UpdateNewsletterSettings", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 } ``` ### Clear the saved overrides Future sends use the existing workspace defaults. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/newsletters.UpdateNewsletterSettings' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "sender_name": null, "reply_to": null }' ``` #### TypeScript ```typescript 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/newsletters.UpdateNewsletterSettings", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "sender_name": null, "reply_to": 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 = { "sender_name": None, "reply_to": None } request = Request( "https://api.brigg.app/v1/operations/newsletters.UpdateNewsletterSettings", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "sender_name": { "anyOf": [ { "type": "string", "maxLength": 120, "description": "New sender display-name override. Omit to preserve it; null or blank clears it to the workspace default. Quotes, backslashes and line breaks are removed; the saved name is trimmed to 78 characters." }, { "type": "null", "description": "New sender display-name override. Omit to preserve it; null or blank clears it to the workspace default. Quotes, backslashes and line breaks are removed; the saved name is trimmed to 78 characters." } ], "description": "New sender display-name override. Omit to preserve it; null or blank clears it to the workspace default. Quotes, backslashes and line breaks are removed; the saved name is trimmed to 78 characters." }, "reply_to": { "anyOf": [ { "type": "string", "maxLength": 254, "description": "Single valid reply email address. Omit to preserve it; null or blank clears the saved override. This does not change the authenticated sending domain." }, { "type": "null", "description": "Single valid reply email address. Omit to preserve it; null or blank clears the saved override. This does not change the authenticated sending domain." } ], "description": "Single valid reply email address. Omit to preserve it; null or blank clears the saved override. This does not change the authenticated sending domain." } }, "additionalProperties": false, "examples": [ { "sender_name": "Northstar team", "reply_to": "team@example.com" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "The settings were saved. Read GetNewsletterSettings for the resulting values; no email has been sent." } }, "required": [ "ok" ], "additionalProperties": false, "examples": [ { "ok": true } ] } ``` --- # List newsletter schedules List recurring newsletter schedules and their next preparation time. Open review_url to inspect or manage a series in Brigg. POST https://api.brigg.app/v1/operations/newsletters.ListNewsletterSchedules ## Access & visibility Allow `newsletters.ListNewsletterSchedules` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/permissions) ## Request No parameters. Send an empty JSON object (`{}`). ## Preparation, review and sending are separate A schedule produces issues. An issue has its own `issue_id`; its generated content has a separate `newsletter_id`. Read [Get newsletter issue](/developers/reference/newsletters/GetNewsletterIssue) until that content and its `review_url` are available. A schedule start or run response does not mean preparation has finished. Public callers use manual approval. A person reviews and sends the issue in Brigg; preparing content or saving a draft does not send it to the audience. [Send newsletter test email](/developers/reference/newsletters/SendNewsletterTestEmail) sends a test to the acting member, not the subscriber list. A schedule's `start_at` is Unix milliseconds and its `timezone` is an IANA zone used for recurrence. `run_now` creates an extra first issue without consuming the first scheduled slot. Pause a schedule with `paused: true` when you want to stop future preparation while retaining the schedule. ## Response Returns **200 OK** with a JSON body. This operation has no continuation cursor. An empty `items` array means no matching visible results were returned. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [Newsletter schedule](#newsletter-schedule-response-items) | Yes | Newsletter schedules in the workspace, including paused schedules. This operation has no cursor pagination. | ### Newsletter schedule · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `schedule_id` | string | Yes | Schedule ID used to read, update or list the schedule's issues. | | `name` | string | Yes | Display name of the newsletter schedule. | | `frequency` | string | Yes | Recurring preparation cadence: weekly is every week, biweekly is every two weeks, monthly is every month in the schedule’s time zone. | | `timezone` | string | Yes | IANA time zone, for example Europe/Oslo. | | `next_run_at` | integer or null | Yes | Next planned preparation slot in Unix milliseconds, or null when no slot is scheduled, including while paused. It is not an email-send timestamp. | | `paused` | boolean | Yes | Whether new scheduled issue generation is paused. Existing issues remain available. | | `approval` | string | Yes | Approval policy for generated issues. Public API schedules require manual review and sending in Brigg. Allowed: `"manual"`, `"automatic"`. | | `review_url` | string | Yes | Open the schedule in Brigg to review its setup and issues. Format: uri. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [List newsletter issues](/developers/reference/newsletters/ListNewsletterIssues) - [Get newsletter issue](/developers/reference/newsletters/GetNewsletterIssue) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/newsletters.ListNewsletterSchedules' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{}' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/newsletters.ListNewsletterSchedules", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/newsletters.ListNewsletterSchedules", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "schedule_id": "schedule_customer_updates", "name": "Customer updates", "frequency": "monthly", "timezone": "Europe/Oslo", "next_run_at": 1796893200000, "paused": false, "approval": "manual", "review_url": "https://example.com/newsletters/schedule_customer_updates" } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": {}, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "schedule_id": { "type": "string", "description": "Schedule ID used to read, update or list the schedule's issues.", "examples": [ "schedule_customer_updates" ] }, "name": { "type": "string", "description": "Display name of the newsletter schedule.", "examples": [ "Customer updates" ] }, "frequency": { "type": "string", "description": "Recurring preparation cadence: weekly is every week, biweekly is every two weeks, monthly is every month in the schedule’s time zone.", "examples": [ "monthly" ] }, "timezone": { "type": "string", "description": "IANA time zone, for example Europe/Oslo." }, "next_run_at": { "type": [ "integer", "null" ], "description": "Next planned preparation slot in Unix milliseconds, or null when no slot is scheduled, including while paused. It is not an email-send timestamp.", "examples": [ 1796893200000 ] }, "paused": { "type": "boolean", "description": "Whether new scheduled issue generation is paused. Existing issues remain available.", "examples": [ false ] }, "approval": { "type": "string", "enum": [ "manual", "automatic" ], "description": "Approval policy for generated issues. Public API schedules require manual review and sending in Brigg.", "examples": [ "manual" ] }, "review_url": { "type": "string", "format": "uri", "description": "Open the schedule in Brigg to review its setup and issues.", "examples": [ "https://example.com/newsletters/schedule_customer_updates" ] } }, "required": [ "schedule_id", "name", "frequency", "timezone", "next_run_at", "paused", "approval", "review_url" ], "additionalProperties": false, "title": "Newsletter schedule" }, "description": "Newsletter schedules in the workspace, including paused schedules. This operation has no cursor pagination." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "schedule_id": "schedule_customer_updates", "name": "Customer updates", "frequency": "monthly", "timezone": "Europe/Oslo", "next_run_at": 1796893200000, "paused": false, "approval": "manual", "review_url": "https://example.com/newsletters/schedule_customer_updates" } ] } ] } ``` --- # Create newsletter schedule Create a recurring newsletter preparation schedule. Public callers use manual approval: each prepared issue must be reviewed and sent by a person in Brigg. Returns schedule_id and, when run_now is true, the first issue_id. Poll GetNewsletterIssue for preparation status. POST https://api.brigg.app/v1/operations/newsletters.CreateNewsletterSchedule ## Access & visibility Allow `newsletters.CreateNewsletterSchedule` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `name` | string | Yes | Display name. At least 1 character. At most 120 characters. | | `frequency` | string | Yes | How often the schedule prepares a newsletter issue. Allowed: `"weekly"`, `"biweekly"`, `"monthly"`. | | `start_at` | integer | Yes | Epoch ms of the first issue, wall-clock in `timezone`. Greater than 0. | | `timezone` | string | Yes | IANA time zone, for example Europe/Oslo. At least 1 character. At most 64 characters. | | `audience` | [object](#request-audience) | No | Selected recipients or audience definition for this newsletter. | | `sources` | [object](#request-sources) | No | Sources used to prepare the newsletter's content. | | `instructions_md` | string or null | No | Editorial instructions in Markdown for preparing the newsletter. | | `template_id` | string or null | No | Select an existing newsletter and use its content_id as the schedule template. A Word or meeting template cannot be used here. [workspace.ListBundles](/developers/reference/workspace/ListBundles). | | `approval` | string | Yes | Each issue is prepared for a person to review and send in Brigg. Automatic sending must be configured in Brigg. Always `"manual"`. | | `run_now` | boolean | No | Also mint the first issue immediately, without consuming the first scheduled slot. | ### request.audience | Field | Type | Required | Description | | --- | --- | --- | --- | | `mode` | string | Yes | all selects all contacts; tags selects contacts carrying at least one selected tag; manual uses only the supplied email addresses. Allowed: `"all"`, `"tags"`, `"manual"`. | | `tags` | array of string | Yes | Stable contact tag keys. Used only in tags mode. | | `extra` | array of string | Yes | Explicit additional email addresses. In manual mode these are the entire audience. | ### request.sources | Field | Type | Required | Description | | --- | --- | --- | --- | | `website` | [object](#request-sources-website) | Yes | Company website URL, including https://. | | `blog` | [object](#request-sources-blog) | Yes | Blog content source configured for this newsletter. | | `web_search` | boolean | Yes | Research relevant public web sources. | | `meetings` | boolean | Yes | Use information from shared workspace meetings. | | `new_clients` | boolean | Yes | Use recently added CRM companies. | | `instructions` | string | Yes | Additional instructions for preparing each issue. | ### request.sources.website | Field | Type | Required | Description | | --- | --- | --- | --- | | `enabled` | boolean | Yes | Whether this feature is enabled. | | `url` | string | Yes | Absolute URL, including its scheme. | ### request.sources.blog | Field | Type | Required | Description | | --- | --- | --- | --- | | `enabled` | boolean | Yes | Whether this feature is enabled. | | `url` | string | Yes | Absolute URL, including its scheme. | ## Preparation, review and sending are separate A schedule produces issues. An issue has its own `issue_id`; its generated content has a separate `newsletter_id`. Read [Get newsletter issue](/developers/reference/newsletters/GetNewsletterIssue) until that content and its `review_url` are available. A schedule start or run response does not mean preparation has finished. Public callers use manual approval. A person reviews and sends the issue in Brigg; preparing content or saving a draft does not send it to the audience. [Send newsletter test email](/developers/reference/newsletters/SendNewsletterTestEmail) sends a test to the acting member, not the subscriber list. A schedule's `start_at` is Unix milliseconds and its `timezone` is an IANA zone used for recurrence. `run_now` creates an extra first issue without consuming the first scheduled slot. Pause a schedule with `paused: true` when you want to stop future preparation while retaining the schedule. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `schedule_id` | string | Yes | Schedule identifier. | | `next_run_at` | number | Yes | Epoch ms of the first scheduled issue. | | `issue` | [object](#response-issue) or null | Yes | The first issue's outcome; null unless run_now was given. | ### response.issue | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | | `issue_id` | string | No | Issue identifier. | | `newsletter_id` | string | No | Newsletter identifier. | | `error` | string | No | Failure details for the preparation attempt. | | `message` | string | No | Status or failure explanation returned for the preparation attempt. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | ## Next steps - [List newsletter schedules](/developers/reference/newsletters/ListNewsletterSchedules) - [List newsletter issues](/developers/reference/newsletters/ListNewsletterIssues) - [Get newsletter issue](/developers/reference/newsletters/GetNewsletterIssue) - [List bundles](/developers/reference/workspace/ListBundles) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/newsletters.CreateNewsletterSchedule' \ -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 '{ "name": "Example project", "frequency": "weekly", "start_at": 1794301200000, "timezone": "Europe/Oslo", "approval": "manual" }' ``` #### 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/newsletters.CreateNewsletterSchedule", { 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({ "name": "Example project", "frequency": "weekly", "start_at": 1794301200000, "timezone": "Europe/Oslo", "approval": "manual" }), }); 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 = { "name": "Example project", "frequency": "weekly", "start_at": 1794301200000, "timezone": "Europe/Oslo", "approval": "manual" } request = Request( "https://api.brigg.app/v1/operations/newsletters.CreateNewsletterSchedule", 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 { "schedule_id": "e_example", "next_run_at": 1794301200000, "issue": null } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 120, "description": "Display name." }, "frequency": { "type": "string", "enum": [ "weekly", "biweekly", "monthly" ], "description": "How often the schedule prepares a newsletter issue." }, "start_at": { "type": "integer", "exclusiveMinimum": 0, "description": "Epoch ms of the first issue, wall-clock in `timezone`." }, "timezone": { "type": "string", "minLength": 1, "maxLength": 64, "description": "IANA time zone, for example Europe/Oslo." }, "audience": { "type": "object", "properties": { "mode": { "type": "string", "enum": [ "all", "tags", "manual" ], "description": "all selects all contacts; tags selects contacts carrying at least one selected tag; manual uses only the supplied email addresses." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable contact tag keys. Used only in tags mode." }, "extra": { "type": "array", "items": { "type": "string", "pattern": "^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$" }, "description": "Explicit additional email addresses. In manual mode these are the entire audience." } }, "required": [ "mode", "tags", "extra" ], "additionalProperties": false, "$schema": "http://json-schema.org/draft-07/schema#", "description": "Selected recipients or audience definition for this newsletter." }, "sources": { "type": "object", "properties": { "website": { "type": "object", "properties": { "enabled": { "type": "boolean", "description": "Whether this feature is enabled." }, "url": { "type": "string", "description": "Absolute URL, including its scheme." } }, "required": [ "enabled", "url" ], "additionalProperties": false, "description": "Company website URL, including https://." }, "blog": { "type": "object", "properties": { "enabled": { "type": "boolean", "description": "Whether this feature is enabled." }, "url": { "type": "string", "description": "Absolute URL, including its scheme." } }, "required": [ "enabled", "url" ], "additionalProperties": false, "description": "Blog content source configured for this newsletter." }, "web_search": { "type": "boolean", "description": "Research relevant public web sources." }, "meetings": { "type": "boolean", "description": "Use information from shared workspace meetings." }, "new_clients": { "type": "boolean", "description": "Use recently added CRM companies." }, "instructions": { "type": "string", "description": "Additional instructions for preparing each issue." } }, "required": [ "website", "blog", "web_search", "meetings", "new_clients", "instructions" ], "additionalProperties": false, "$schema": "http://json-schema.org/draft-07/schema#", "description": "Sources used to prepare the newsletter's content." }, "instructions_md": { "anyOf": [ { "type": "string", "maxLength": 4000 }, { "type": "null" } ], "description": "Editorial instructions in Markdown for preparing the newsletter." }, "template_id": { "anyOf": [ { "type": "string", "maxLength": 80 }, { "type": "null" } ], "description": "Select an existing newsletter and use its content_id as the schedule template. A Word or meeting template cannot be used here. [workspace.ListBundles](/developers/reference/workspace/ListBundles)." }, "approval": { "type": "string", "const": "manual", "description": "Each issue is prepared for a person to review and send in Brigg. Automatic sending must be configured in Brigg." }, "run_now": { "type": "boolean", "description": "Also mint the first issue immediately, without consuming the first scheduled slot." } }, "required": [ "name", "frequency", "start_at", "timezone", "approval" ], "additionalProperties": false, "examples": [ { "name": "Example project", "frequency": "weekly", "start_at": 1794301200000, "timezone": "Europe/Oslo", "approval": "manual" } ] } ``` ```json-schema-response { "type": "object", "properties": { "schedule_id": { "type": "string", "description": "Schedule identifier." }, "next_run_at": { "type": "number", "description": "Epoch ms of the first scheduled issue." }, "issue": { "type": [ "object", "null" ], "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." }, "issue_id": { "type": "string", "description": "Issue identifier." }, "newsletter_id": { "type": "string", "description": "Newsletter identifier." }, "error": { "type": "string", "description": "Failure details for the preparation attempt." }, "message": { "type": "string", "description": "Status or failure explanation returned for the preparation attempt." } }, "required": [ "ok" ], "description": "The first issue's outcome; null unless run_now was given.", "additionalProperties": false } }, "required": [ "schedule_id", "next_run_at", "issue" ], "additionalProperties": false, "examples": [ { "schedule_id": "e_example", "next_run_at": 1794301200000, "issue": null } ] } ``` --- # Delete newsletter schedule Delete a newsletter schedule. Previously created newsletter documents are retained. POST https://api.brigg.app/v1/operations/newsletters.DeleteNewsletterSchedule ## Access & visibility Allow `newsletters.DeleteNewsletterSchedule` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `schedule_id` | string | Yes | Use schedule_id from the schedule listing. A schedule can produce multiple issues. [newsletters.ListNewsletterSchedules](/developers/reference/newsletters/ListNewsletterSchedules). At least 1 character. | ## Preparation, review and sending are separate A schedule produces issues. An issue has its own `issue_id`; its generated content has a separate `newsletter_id`. Read [Get newsletter issue](/developers/reference/newsletters/GetNewsletterIssue) until that content and its `review_url` are available. A schedule start or run response does not mean preparation has finished. Public callers use manual approval. A person reviews and sends the issue in Brigg; preparing content or saving a draft does not send it to the audience. [Send newsletter test email](/developers/reference/newsletters/SendNewsletterTestEmail) sends a test to the acting member, not the subscriber list. A schedule's `start_at` is Unix milliseconds and its `timezone` is an IANA zone used for recurrence. `run_now` creates an extra first issue without consuming the first scheduled slot. Pause a schedule with `paused: true` when you want to stop future preparation while retaining the schedule. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | ## Next steps - [List newsletter schedules](/developers/reference/newsletters/ListNewsletterSchedules) - [List newsletter issues](/developers/reference/newsletters/ListNewsletterIssues) - [Get newsletter issue](/developers/reference/newsletters/GetNewsletterIssue) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/newsletters.DeleteNewsletterSchedule' \ -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 '{ "schedule_id": "e_example" }' ``` #### 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/newsletters.DeleteNewsletterSchedule", { 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({ "schedule_id": "e_example" }), }); 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 = { "schedule_id": "e_example" } request = Request( "https://api.brigg.app/v1/operations/newsletters.DeleteNewsletterSchedule", 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 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "schedule_id": { "type": "string", "minLength": 1, "description": "Use schedule_id from the schedule listing. A schedule can produce multiple issues. [newsletters.ListNewsletterSchedules](/developers/reference/newsletters/ListNewsletterSchedules)." } }, "required": [ "schedule_id" ], "additionalProperties": false, "examples": [ { "schedule_id": "e_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." } }, "required": [ "ok" ], "additionalProperties": false, "examples": [ { "ok": true } ] } ``` --- # Run newsletter schedule Prepare an extra issue of a manually approved newsletter series without moving its scheduled date. Returns issue_id for GetNewsletterIssue. This does not send the issue; a person reviews and sends it in Brigg. POST https://api.brigg.app/v1/operations/newsletters.RunNewsletterSchedule ## Access & visibility Allow `newsletters.RunNewsletterSchedule` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `schedule_id` | string | Yes | Use schedule_id from the schedule listing. A schedule can produce multiple issues. [newsletters.ListNewsletterSchedules](/developers/reference/newsletters/ListNewsletterSchedules). At least 1 character. | ## Preparation, review and sending are separate A schedule produces issues. An issue has its own `issue_id`; its generated content has a separate `newsletter_id`. Read [Get newsletter issue](/developers/reference/newsletters/GetNewsletterIssue) until that content and its `review_url` are available. A schedule start or run response does not mean preparation has finished. Public callers use manual approval. A person reviews and sends the issue in Brigg; preparing content or saving a draft does not send it to the audience. [Send newsletter test email](/developers/reference/newsletters/SendNewsletterTestEmail) sends a test to the acting member, not the subscriber list. A schedule's `start_at` is Unix milliseconds and its `timezone` is an IANA zone used for recurrence. `run_now` creates an extra first issue without consuming the first scheduled slot. Pause a schedule with `paused: true` when you want to stop future preparation while retaining the schedule. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | | `issue_id` | string | Yes | Issue identifier. | | `newsletter_id` | string | Yes | Newsletter identifier. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | ## Next steps - [List newsletter schedules](/developers/reference/newsletters/ListNewsletterSchedules) - [List newsletter issues](/developers/reference/newsletters/ListNewsletterIssues) - [Get newsletter issue](/developers/reference/newsletters/GetNewsletterIssue) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/newsletters.RunNewsletterSchedule' \ -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 '{ "schedule_id": "e_example" }' ``` #### 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/newsletters.RunNewsletterSchedule", { 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({ "schedule_id": "e_example" }), }); 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 = { "schedule_id": "e_example" } request = Request( "https://api.brigg.app/v1/operations/newsletters.RunNewsletterSchedule", 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, "issue_id": "e_example", "newsletter_id": "e_example" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "schedule_id": { "type": "string", "minLength": 1, "description": "Use schedule_id from the schedule listing. A schedule can produce multiple issues. [newsletters.ListNewsletterSchedules](/developers/reference/newsletters/ListNewsletterSchedules)." } }, "required": [ "schedule_id" ], "additionalProperties": false, "examples": [ { "schedule_id": "e_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." }, "issue_id": { "type": "string", "description": "Issue identifier." }, "newsletter_id": { "type": "string", "description": "Newsletter identifier." } }, "required": [ "ok", "issue_id", "newsletter_id" ], "additionalProperties": false, "examples": [ { "ok": true, "issue_id": "e_example", "newsletter_id": "e_example" } ] } ``` --- # Update newsletter schedule Update a newsletter series using schedule_id, or pause future preparation. Public callers can select manual approval; automatic delivery must be configured in Brigg. Changing a schedule does not resend an existing issue. POST https://api.brigg.app/v1/operations/newsletters.UpdateNewsletterSchedule ## Access & visibility Allow `newsletters.UpdateNewsletterSchedule` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `schedule_id` | string | Yes | Use schedule_id from the schedule listing. A schedule can produce multiple issues. [newsletters.ListNewsletterSchedules](/developers/reference/newsletters/ListNewsletterSchedules). At least 1 character. | | `name` | string | No | Display name. At least 1 character. At most 120 characters. | | `frequency` | string | No | How often the schedule prepares a newsletter issue. Allowed: `"weekly"`, `"biweekly"`, `"monthly"`. | | `start_at` | integer | No | Epoch ms of the first issue, wall-clock in `timezone`. Greater than 0. | | `timezone` | string | No | IANA time zone, for example Europe/Oslo. At least 1 character. At most 64 characters. | | `audience` | [object](#request-audience) | No | Selected recipients or audience definition for this newsletter. | | `sources` | [object](#request-sources) | No | Sources used to prepare the newsletter's content. | | `instructions_md` | string or null | No | Editorial instructions in Markdown for preparing the newsletter. | | `template_id` | string or null | No | Select an existing newsletter and use its content_id as the schedule template. A Word or meeting template cannot be used here. [workspace.ListBundles](/developers/reference/workspace/ListBundles). | | `approval` | string | No | Each issue is prepared for a person to review and send in Brigg. Automatic sending must be configured in Brigg. Always `"manual"`. | | `paused` | boolean | No | Pause (true) or resume (false) the series. | ### request.audience | Field | Type | Required | Description | | --- | --- | --- | --- | | `mode` | string | Yes | all selects all contacts; tags selects contacts carrying at least one selected tag; manual uses only the supplied email addresses. Allowed: `"all"`, `"tags"`, `"manual"`. | | `tags` | array of string | Yes | Stable contact tag keys. Used only in tags mode. | | `extra` | array of string | Yes | Explicit additional email addresses. In manual mode these are the entire audience. | ### request.sources | Field | Type | Required | Description | | --- | --- | --- | --- | | `website` | [object](#request-sources-website) | Yes | Company website URL, including https://. | | `blog` | [object](#request-sources-blog) | Yes | Blog content source configured for this newsletter. | | `web_search` | boolean | Yes | Research relevant public web sources. | | `meetings` | boolean | Yes | Use information from shared workspace meetings. | | `new_clients` | boolean | Yes | Use recently added CRM companies. | | `instructions` | string | Yes | Additional instructions for preparing each issue. | ### request.sources.website | Field | Type | Required | Description | | --- | --- | --- | --- | | `enabled` | boolean | Yes | Whether this feature is enabled. | | `url` | string | Yes | Absolute URL, including its scheme. | ### request.sources.blog | Field | Type | Required | Description | | --- | --- | --- | --- | | `enabled` | boolean | Yes | Whether this feature is enabled. | | `url` | string | Yes | Absolute URL, including its scheme. | ## Preparation, review and sending are separate A schedule produces issues. An issue has its own `issue_id`; its generated content has a separate `newsletter_id`. Read [Get newsletter issue](/developers/reference/newsletters/GetNewsletterIssue) until that content and its `review_url` are available. A schedule start or run response does not mean preparation has finished. Public callers use manual approval. A person reviews and sends the issue in Brigg; preparing content or saving a draft does not send it to the audience. [Send newsletter test email](/developers/reference/newsletters/SendNewsletterTestEmail) sends a test to the acting member, not the subscriber list. A schedule's `start_at` is Unix milliseconds and its `timezone` is an IANA zone used for recurrence. `run_now` creates an extra first issue without consuming the first scheduled slot. Pause a schedule with `paused: true` when you want to stop future preparation while retaining the schedule. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | | `next_run_at` | number or null | Yes | Epoch ms of the next issue; null while the series is paused. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | ## Next steps - [List newsletter schedules](/developers/reference/newsletters/ListNewsletterSchedules) - [List newsletter issues](/developers/reference/newsletters/ListNewsletterIssues) - [Get newsletter issue](/developers/reference/newsletters/GetNewsletterIssue) - [List bundles](/developers/reference/workspace/ListBundles) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/newsletters.UpdateNewsletterSchedule' \ -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 '{ "schedule_id": "e_example" }' ``` #### 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/newsletters.UpdateNewsletterSchedule", { 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({ "schedule_id": "e_example" }), }); 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 = { "schedule_id": "e_example" } request = Request( "https://api.brigg.app/v1/operations/newsletters.UpdateNewsletterSchedule", 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, "next_run_at": null } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "schedule_id": { "type": "string", "minLength": 1, "description": "Use schedule_id from the schedule listing. A schedule can produce multiple issues. [newsletters.ListNewsletterSchedules](/developers/reference/newsletters/ListNewsletterSchedules)." }, "name": { "type": "string", "minLength": 1, "maxLength": 120, "description": "Display name." }, "frequency": { "type": "string", "enum": [ "weekly", "biweekly", "monthly" ], "description": "How often the schedule prepares a newsletter issue." }, "start_at": { "type": "integer", "exclusiveMinimum": 0, "description": "Epoch ms of the first issue, wall-clock in `timezone`." }, "timezone": { "type": "string", "minLength": 1, "maxLength": 64, "description": "IANA time zone, for example Europe/Oslo." }, "audience": { "type": "object", "properties": { "mode": { "type": "string", "enum": [ "all", "tags", "manual" ], "description": "all selects all contacts; tags selects contacts carrying at least one selected tag; manual uses only the supplied email addresses." }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Stable contact tag keys. Used only in tags mode." }, "extra": { "type": "array", "items": { "type": "string", "pattern": "^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$" }, "description": "Explicit additional email addresses. In manual mode these are the entire audience." } }, "required": [ "mode", "tags", "extra" ], "additionalProperties": false, "$schema": "http://json-schema.org/draft-07/schema#", "description": "Selected recipients or audience definition for this newsletter." }, "sources": { "type": "object", "properties": { "website": { "type": "object", "properties": { "enabled": { "type": "boolean", "description": "Whether this feature is enabled." }, "url": { "type": "string", "description": "Absolute URL, including its scheme." } }, "required": [ "enabled", "url" ], "additionalProperties": false, "description": "Company website URL, including https://." }, "blog": { "type": "object", "properties": { "enabled": { "type": "boolean", "description": "Whether this feature is enabled." }, "url": { "type": "string", "description": "Absolute URL, including its scheme." } }, "required": [ "enabled", "url" ], "additionalProperties": false, "description": "Blog content source configured for this newsletter." }, "web_search": { "type": "boolean", "description": "Research relevant public web sources." }, "meetings": { "type": "boolean", "description": "Use information from shared workspace meetings." }, "new_clients": { "type": "boolean", "description": "Use recently added CRM companies." }, "instructions": { "type": "string", "description": "Additional instructions for preparing each issue." } }, "required": [ "website", "blog", "web_search", "meetings", "new_clients", "instructions" ], "additionalProperties": false, "$schema": "http://json-schema.org/draft-07/schema#", "description": "Sources used to prepare the newsletter's content." }, "instructions_md": { "anyOf": [ { "type": "string", "maxLength": 4000 }, { "type": "null" } ], "description": "Editorial instructions in Markdown for preparing the newsletter." }, "template_id": { "anyOf": [ { "type": "string", "maxLength": 80 }, { "type": "null" } ], "description": "Select an existing newsletter and use its content_id as the schedule template. A Word or meeting template cannot be used here. [workspace.ListBundles](/developers/reference/workspace/ListBundles)." }, "approval": { "type": "string", "const": "manual", "description": "Each issue is prepared for a person to review and send in Brigg. Automatic sending must be configured in Brigg." }, "paused": { "type": "boolean", "description": "Pause (true) or resume (false) the series." } }, "required": [ "schedule_id" ], "additionalProperties": false, "examples": [ { "schedule_id": "e_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." }, "next_run_at": { "type": [ "number", "null" ], "description": "Epoch ms of the next issue; null while the series is paused." } }, "required": [ "ok", "next_run_at" ], "additionalProperties": false, "examples": [ { "ok": true, "next_run_at": null } ] } ``` --- # Get signing document Get a temporary download link for the original PDF or completed signed archive. Only people and credentials with access to the signing request can obtain the link. POST https://api.brigg.app/v1/operations/signing.GetSigningDocument ## Access & visibility Allow `signing.GetSigningDocument` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `signing_request_id` | string | Yes | Keep the signing_request_id returned when invitations were requested. A file_id or signer_id identifies something else. [signing.RequestFileSignatures](/developers/reference/signing/RequestFileSignatures). At least 1 character. | | `version` | string | No | Which document to download: the original source or the completed signed archive. Allowed: `"original"`, `"signed"`. Default: `"signed"`. | ## Follow one signing request through completion [Upload a readable PDF](/developers/files), then [request signatures](/developers/reference/signing/RequestFileSignatures) and keep `signing_request_id`. The request keeps a fixed source; replacing the original file later does not change what recipients sign. Read [Get signing request](/developers/reference/signing/GetSigningRequest) for per-recipient progress. `completed` means everyone signed, but the archive can still be preparing: wait for non-null `file_id` before requesting the signed PDF. [Get signing document](/developers/reference/signing/GetSigningDocument) returns a short-lived URL for either the fixed original or the signed archive. Notification failures do not undo the signing request. Remind the affected pending recipients instead of creating a duplicate request. Recipients sign themselves; a delegated API call cannot supply a recipient's signature. See the [complete signing workflow](/developers/signing). ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `url` | string | Yes | Absolute URL, including its scheme. | | `filename` | string | Yes | Original filename, including its extension. | | `expires_at` | number | Yes | Signing deadline in Unix milliseconds. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | | 409 | `document_not_ready` | The requested original or signed archive is not available yet; read GetSigningRequest before retrying. | ## Next steps - [Get signing request](/developers/reference/signing/GetSigningRequest) - [Remind signers](/developers/reference/signing/RemindSigners) - [Send a document for signing](/developers/signing) - [Request file signatures](/developers/reference/signing/RequestFileSignatures) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/signing.GetSigningDocument' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "signing_request_id": "sig_example", "version": "signed" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/signing.GetSigningDocument", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "signing_request_id": "sig_example", "version": "signed" }), }); 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 payload = { "signing_request_id": "sig_example", "version": "signed" } request = Request( "https://api.brigg.app/v1/operations/signing.GetSigningDocument", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "url": "https://example.com/temporary-signed-download", "filename": "Consulting agreement.pdf", "expires_at": 1794301500000 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "signing_request_id": { "type": "string", "minLength": 1, "description": "Keep the signing_request_id returned when invitations were requested. A file_id or signer_id identifies something else. [signing.RequestFileSignatures](/developers/reference/signing/RequestFileSignatures)." }, "version": { "type": "string", "enum": [ "original", "signed" ], "default": "signed", "description": "Which document to download: the original source or the completed signed archive." } }, "required": [ "signing_request_id" ], "additionalProperties": false, "examples": [ { "signing_request_id": "sig_example", "version": "signed" } ] } ``` ```json-schema-response { "type": "object", "properties": { "url": { "type": "string", "description": "Absolute URL, including its scheme." }, "filename": { "type": "string", "description": "Original filename, including its extension." }, "expires_at": { "type": "number", "description": "Signing deadline in Unix milliseconds." } }, "required": [ "url", "filename", "expires_at" ], "additionalProperties": false, "examples": [ { "url": "https://example.com/temporary-signed-download", "filename": "Consulting agreement.pdf", "expires_at": 1794301500000 } ] } ``` --- # Get signing request Read a signing request and each recipient’s progress. A completed request may still be preparing its signed PDF. A workspace key can read requests created by that key. POST https://api.brigg.app/v1/operations/signing.GetSigningRequest ## Access & visibility Allow `signing.GetSigningRequest` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `signing_request_id` | string | Yes | Keep the signing_request_id returned when invitations were requested. A file_id or signer_id identifies something else. [signing.RequestFileSignatures](/developers/reference/signing/RequestFileSignatures). At least 1 character. | ## Follow one signing request through completion [Upload a readable PDF](/developers/files), then [request signatures](/developers/reference/signing/RequestFileSignatures) and keep `signing_request_id`. The request keeps a fixed source; replacing the original file later does not change what recipients sign. Read [Get signing request](/developers/reference/signing/GetSigningRequest) for per-recipient progress. `completed` means everyone signed, but the archive can still be preparing: wait for non-null `file_id` before requesting the signed PDF. [Get signing document](/developers/reference/signing/GetSigningDocument) returns a short-lived URL for either the fixed original or the signed archive. Notification failures do not undo the signing request. Remind the affected pending recipients instead of creating a duplicate request. Recipients sign themselves; a delegated API call cannot supply a recipient's signature. See the [complete signing workflow](/developers/signing). ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `signing_request_id` | string | Yes | Signing request identifier. | | `title` | string | Yes | Display title. | | `status` | string | Yes | Request state: pending is awaiting signatures; completed means every recipient signed; cancelled stops the request; expired means a pending request passed its deadline. Completed does not by itself guarantee an archived file. Allowed: `"pending"`, `"completed"`, `"cancelled"`, `"expired"`. | | `signature_method` | string | Yes | Signature method required for the request. Allowed: `"standard"`, `"bankid"`. | | `expires_at` | number | Yes | Signing deadline in Unix milliseconds. | | `created_at` | number | Yes | Creation time in Unix milliseconds. | | `completed_at` | number or null | Yes | Time signing completed, in Unix milliseconds, or null while incomplete. | | `source` | [object](#response-source) | Yes | Original document identity preserved for this signing request. | | `file_id` | string or null | Yes | Signed archive identity, or null when not yet available. Request version=signed from GetSigningDocument only after this is present. | | `signers` | array of [object](#response-signers) | Yes | Named recipients and their individual signature states. | ### response.source | Field | Type | Required | Description | | --- | --- | --- | --- | | `type` | string | Yes | Type identifying which variant of this model applies. Allowed: `"file"`, `"document"`, `"registration"`. | | `id` | string | Yes | Original identity, interpreted with source.type: file means the uploaded file_id, document means the generated document_id, and registration means the business registration_id. It is not the signed archive's file_id. | | `sha256` | string | No | SHA-256 hex digest of the fixed uploaded PDF source, when included. Replacing the original file does not change that signing source. | ### response.signers[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `signer_id` | string | Yes | Signer identifier. | | `email` | string | Yes | Email address. | | `name` | string or null | Yes | Display name. | | `status` | string | Yes | This recipient's state: pending has not signed, signed completed their signature, declined refused. It is independent of archive creation and is not the request's overall state. Allowed: `"pending"`, `"signed"`, `"declined"`. | | `signed_at` | number or null | Yes | Unix millisecond time of this recipient's signature, or null if they have not signed. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The request is unavailable to this identity. A workspace-only credential can read its own initiated requests; member delegation also checks that member's signing access. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [Get signing document](/developers/reference/signing/GetSigningDocument) - [List signing events](/developers/reference/signing/ListSigningEvents) - [Finalize signing](/developers/reference/signing/FinalizeSigning) - [Remind signers](/developers/reference/signing/RemindSigners) - [Request file signatures](/developers/reference/signing/RequestFileSignatures) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### A recipient still needs to sign The source PDF and future signed archive have distinct identities. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/signing.GetSigningRequest' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "signing_request_id": "sig_project_agreement" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/signing.GetSigningRequest", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "signing_request_id": "sig_project_agreement" }), }); 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 payload = { "signing_request_id": "sig_project_agreement" } request = Request( "https://api.brigg.app/v1/operations/signing.GetSigningRequest", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "signing_request_id": "sig_project_agreement", "title": "Project agreement", "status": "pending", "signature_method": "standard", "expires_at": 1794906000000, "created_at": 1794301200000, "completed_at": null, "source": { "type": "file", "id": "f_agreement", "sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" }, "file_id": null, "signers": [ { "signer_id": "signer_jamie", "email": "jamie@example.com", "name": "Jamie Lee", "status": "pending", "signed_at": null } ] } ``` ### Signatures and archive are ready Download the signed version through GetSigningDocument. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/signing.GetSigningRequest' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "signing_request_id": "sig_project_agreement" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/signing.GetSigningRequest", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "signing_request_id": "sig_project_agreement" }), }); 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 payload = { "signing_request_id": "sig_project_agreement" } request = Request( "https://api.brigg.app/v1/operations/signing.GetSigningRequest", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "signing_request_id": "sig_project_agreement", "title": "Project agreement", "status": "completed", "signature_method": "standard", "expires_at": 1794906000000, "created_at": 1794301200000, "completed_at": 1794304800000, "source": { "type": "file", "id": "f_agreement", "sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" }, "file_id": "f_signed_agreement", "signers": [ { "signer_id": "signer_jamie", "email": "jamie@example.com", "name": "Jamie Lee", "status": "signed", "signed_at": 1794304800000 } ] } ``` ### Everyone signed; archive not ready Wait and re-read. FinalizeSigning can recover an interrupted archive step; never substitute the original for the signed result. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/signing.GetSigningRequest' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "signing_request_id": "sig_project_agreement" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/signing.GetSigningRequest", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "signing_request_id": "sig_project_agreement" }), }); 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 payload = { "signing_request_id": "sig_project_agreement" } request = Request( "https://api.brigg.app/v1/operations/signing.GetSigningRequest", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "signing_request_id": "sig_project_agreement", "title": "Project agreement", "status": "completed", "signature_method": "standard", "expires_at": 1794906000000, "created_at": 1794301200000, "completed_at": 1794304800000, "source": { "type": "file", "id": "f_agreement", "sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" }, "file_id": null, "signers": [ { "signer_id": "signer_jamie", "email": "jamie@example.com", "name": "Jamie Lee", "status": "signed", "signed_at": 1794304800000 } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "signing_request_id": { "type": "string", "minLength": 1, "description": "Keep the signing_request_id returned when invitations were requested. A file_id or signer_id identifies something else. [signing.RequestFileSignatures](/developers/reference/signing/RequestFileSignatures)." } }, "required": [ "signing_request_id" ], "additionalProperties": false, "examples": [ { "signing_request_id": "sig_project_agreement" } ] } ``` ```json-schema-response { "type": "object", "properties": { "signing_request_id": { "type": "string", "description": "Signing request identifier." }, "title": { "type": "string", "description": "Display title." }, "status": { "type": "string", "enum": [ "pending", "completed", "cancelled", "expired" ], "description": "Request state: pending is awaiting signatures; completed means every recipient signed; cancelled stops the request; expired means a pending request passed its deadline. Completed does not by itself guarantee an archived file." }, "signature_method": { "type": "string", "enum": [ "standard", "bankid" ], "description": "Signature method required for the request." }, "expires_at": { "type": "number", "description": "Signing deadline in Unix milliseconds." }, "created_at": { "type": "number", "description": "Creation time in Unix milliseconds." }, "completed_at": { "type": [ "number", "null" ], "description": "Time signing completed, in Unix milliseconds, or null while incomplete." }, "source": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "file", "document", "registration" ], "description": "Type identifying which variant of this model applies." }, "id": { "type": "string", "description": "Original identity, interpreted with source.type: file means the uploaded file_id, document means the generated document_id, and registration means the business registration_id. It is not the signed archive's file_id." }, "sha256": { "type": "string", "description": "SHA-256 hex digest of the fixed uploaded PDF source, when included. Replacing the original file does not change that signing source." } }, "required": [ "type", "id" ], "additionalProperties": false, "description": "Original document identity preserved for this signing request." }, "file_id": { "type": [ "string", "null" ], "description": "Signed archive identity, or null when not yet available. Request version=signed from GetSigningDocument only after this is present." }, "signers": { "type": "array", "items": { "type": "object", "properties": { "signer_id": { "type": "string", "description": "Signer identifier." }, "email": { "type": "string", "description": "Email address." }, "name": { "type": [ "string", "null" ], "description": "Display name." }, "status": { "type": "string", "enum": [ "pending", "signed", "declined" ], "description": "This recipient's state: pending has not signed, signed completed their signature, declined refused. It is independent of archive creation and is not the request's overall state." }, "signed_at": { "type": [ "number", "null" ], "description": "Unix millisecond time of this recipient's signature, or null if they have not signed." } }, "required": [ "signer_id", "email", "name", "status", "signed_at" ], "additionalProperties": false }, "description": "Named recipients and their individual signature states." } }, "required": [ "signing_request_id", "title", "status", "signature_method", "expires_at", "created_at", "completed_at", "source", "file_id", "signers" ], "additionalProperties": false, "examples": [ { "signing_request_id": "sig_project_agreement", "title": "Project agreement", "status": "pending", "signature_method": "standard", "expires_at": 1794906000000, "created_at": 1794301200000, "completed_at": null, "source": { "type": "file", "id": "f_agreement", "sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" }, "file_id": null, "signers": [ { "signer_id": "signer_jamie", "email": "jamie@example.com", "name": "Jamie Lee", "status": "pending", "signed_at": null } ] } ] } ``` --- # List signing events Read the event history of a signing request, oldest first. Use stable event IDs to avoid processing the same event twice. Read GetSigningRequest for current recipient status; events contain no document content or private audit details. POST https://api.brigg.app/v1/operations/signing.ListSigningEvents ## Access & visibility Allow `signing.ListSigningEvents` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `signing_request_id` | string | Yes | Keep the signing_request_id returned when invitations were requested. A file_id or signer_id identifies something else. [signing.RequestFileSignatures](/developers/reference/signing/RequestFileSignatures). At least 1 character. | | `cursor` | string | No | Copy next_cursor from the preceding response. Keep the same filters, sort and credential. | | `limit` | integer | No | Maximum number of results to return in this page. Continue with next_cursor when returned. Default: `50`. Range: 1 to 200. | ## Follow one signing request through completion [Upload a readable PDF](/developers/files), then [request signatures](/developers/reference/signing/RequestFileSignatures) and keep `signing_request_id`. The request keeps a fixed source; replacing the original file later does not change what recipients sign. Read [Get signing request](/developers/reference/signing/GetSigningRequest) for per-recipient progress. `completed` means everyone signed, but the archive can still be preparing: wait for non-null `file_id` before requesting the signed PDF. [Get signing document](/developers/reference/signing/GetSigningDocument) returns a short-lived URL for either the fixed original or the signed archive. Notification failures do not undo the signing request. Remind the affected pending recipients instead of creating a duplicate request. Recipients sign themselves; a delegated API call cannot supply a recipient's signature. See the [complete signing workflow](/developers/signing). ## Response Returns **200 OK** with a JSON body. An empty `items` array means this page contains no matching visible results. Follow `next_cursor` when present. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [Signing event](#signing-event-response-items) | Yes | Recorded events for the selected signing request. Pass next_cursor as cursor to continue when a next cursor is returned. | | `next_cursor` | string or null | Yes | Pass this value as cursor to continue with the same filters, sort and credential. Null when there are no more results. | | `has_more` | boolean | Yes | Whether more event history is available after this page. | ### Signing event · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `event_id` | string | Yes | Unique audit-event ID for deduplication when reading overlapping pages. | | `type` | string | Yes | Recorded signing lifecycle event, such as signing.requested. Allowed: `"signing.requested"`, `"signing.opened"`, `"signing.signed"`, `"signing.cancelled"`, `"signing.deadline_changed"`, `"signing.reminded"`, `"signing.finalized"`. | | `occurred_at` | integer | Yes | Event time in Unix milliseconds. | ## Pagination Pass `next_cursor` as `cursor` on the next request, keeping the same query and acting identity. Stop when `next_cursor` is null. Treat the cursor as opaque; never construct or edit it. ```typescript const query = { "signing_request_id": "sig_example", "limit": 50 }; let cursor; do { const response = await fetch("https://api.brigg.app/v1/operations/signing.ListSigningEvents", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ ...query, ...(cursor ? { cursor } : {}) }), }); const page = await response.json(); if (!response.ok) throw new Error(`${response.status}: ${page.message}`); for (const item of page.items) { console.log(item); // Process or upsert each result. } cursor = page.next_cursor; } while (cursor); ``` ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [Get signing request](/developers/reference/signing/GetSigningRequest) - [Get signing document](/developers/reference/signing/GetSigningDocument) - [Remind signers](/developers/reference/signing/RemindSigners) - [Send a document for signing](/developers/signing) - [Request file signatures](/developers/reference/signing/RequestFileSignatures) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/signing.ListSigningEvents' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "signing_request_id": "sig_example", "limit": 50 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/signing.ListSigningEvents", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "signing_request_id": "sig_example", "limit": 50 }), }); 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 payload = { "signing_request_id": "sig_example", "limit": 50 } request = Request( "https://api.brigg.app/v1/operations/signing.ListSigningEvents", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "event_id": "audit_example", "type": "signing.requested", "occurred_at": 1794301200000 } ], "next_cursor": null, "has_more": false } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "signing_request_id": { "type": "string", "minLength": 1, "description": "Keep the signing_request_id returned when invitations were requested. A file_id or signer_id identifies something else. [signing.RequestFileSignatures](/developers/reference/signing/RequestFileSignatures)." }, "cursor": { "type": "string", "description": "Copy next_cursor from the preceding response. Keep the same filters, sort and credential." }, "limit": { "type": "integer", "minimum": 1, "maximum": 200, "default": 50, "description": "Maximum number of results to return in this page. Continue with next_cursor when returned." } }, "required": [ "signing_request_id" ], "additionalProperties": false, "examples": [ { "signing_request_id": "sig_example", "limit": 50 } ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "event_id": { "type": "string", "description": "Unique audit-event ID for deduplication when reading overlapping pages." }, "type": { "type": "string", "enum": [ "signing.requested", "signing.opened", "signing.signed", "signing.cancelled", "signing.deadline_changed", "signing.reminded", "signing.finalized" ], "description": "Recorded signing lifecycle event, such as signing.requested." }, "occurred_at": { "type": "integer", "description": "Event time in Unix milliseconds." } }, "required": [ "event_id", "type", "occurred_at" ], "additionalProperties": false, "title": "Signing event" }, "description": "Recorded events for the selected signing request. Pass next_cursor as cursor to continue when a next cursor is returned." }, "next_cursor": { "type": [ "string", "null" ], "description": "Pass this value as cursor to continue with the same filters, sort and credential. Null when there are no more results." }, "has_more": { "type": "boolean", "description": "Whether more event history is available after this page." } }, "required": [ "items", "next_cursor", "has_more" ], "additionalProperties": false, "examples": [ { "items": [ { "event_id": "audit_example", "type": "signing.requested", "occurred_at": 1794301200000 } ], "next_cursor": null, "has_more": false } ] } ``` --- # Cancel signing Cancel a pending signature request and disable its signing links. The initiator can then create a new request for the same document. POST https://api.brigg.app/v1/operations/signing.CancelSigning ## Access & visibility Allow `signing.CancelSigning` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `signing_request_id` | string | Yes | Keep the signing_request_id returned when invitations were requested. A file_id or signer_id identifies something else. [signing.RequestFileSignatures](/developers/reference/signing/RequestFileSignatures). At least 1 character. At most 120 characters. | | `reason` | string | No | Explanation for the recipient's reminder outcome. At most 500 characters. | ## Follow one signing request through completion [Upload a readable PDF](/developers/files), then [request signatures](/developers/reference/signing/RequestFileSignatures) and keep `signing_request_id`. The request keeps a fixed source; replacing the original file later does not change what recipients sign. Read [Get signing request](/developers/reference/signing/GetSigningRequest) for per-recipient progress. `completed` means everyone signed, but the archive can still be preparing: wait for non-null `file_id` before requesting the signed PDF. [Get signing document](/developers/reference/signing/GetSigningDocument) returns a short-lived URL for either the fixed original or the signed archive. Notification failures do not undo the signing request. Remind the affected pending recipients instead of creating a duplicate request. Recipients sign themselves; a delegated API call cannot supply a recipient's signature. See the [complete signing workflow](/developers/signing). ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `signing_request_id` | string | Yes | Signing request identifier. | | `status` | string | Yes | Current signing request or recipient state. A completed request may still be preparing its signed PDF. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [Get signing request](/developers/reference/signing/GetSigningRequest) - [Get signing document](/developers/reference/signing/GetSigningDocument) - [Remind signers](/developers/reference/signing/RemindSigners) - [Send a document for signing](/developers/signing) - [Request file signatures](/developers/reference/signing/RequestFileSignatures) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/signing.CancelSigning' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "signing_request_id": "e_example" }' ``` #### TypeScript ```typescript 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/signing.CancelSigning", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "signing_request_id": "e_example" }), }); 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 = { "signing_request_id": "e_example" } request = Request( "https://api.brigg.app/v1/operations/signing.CancelSigning", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "signing_request_id": "e_example", "status": "cancelled" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "signing_request_id": { "type": "string", "minLength": 1, "maxLength": 120, "description": "Keep the signing_request_id returned when invitations were requested. A file_id or signer_id identifies something else. [signing.RequestFileSignatures](/developers/reference/signing/RequestFileSignatures)." }, "reason": { "type": "string", "maxLength": 500, "description": "Explanation for the recipient's reminder outcome." } }, "required": [ "signing_request_id" ], "additionalProperties": false, "examples": [ { "signing_request_id": "e_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "signing_request_id": { "type": "string", "description": "Signing request identifier." }, "status": { "type": "string", "description": "Current signing request or recipient state. A completed request may still be preparing its signed PDF." } }, "required": [ "signing_request_id", "status" ], "additionalProperties": false, "examples": [ { "signing_request_id": "e_example", "status": "cancelled" } ] } ``` --- # Finalize signing Archive a completed signing session as a signed PDF and send copies to the signers. Safe to retry. BankID sessions retain the original signed PDF bytes. POST https://api.brigg.app/v1/operations/signing.FinalizeSigning ## Access & visibility Allow `signing.FinalizeSigning` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `signing_request_id` | string | Yes | The signing_request_id returned when signatures were requested. Read GetSigningRequest first; every recipient must have signed. At least 1 character. At most 120 characters. | ## Recover the archive after everyone has signed The normal recipient flow triggers finalization after the last signature. This operation lets an integration retry that archive step when [Get signing request](/developers/reference/signing/GetSigningRequest) reports completed but has no file_id, for example after an interrupted finalization. It never signs for a recipient or advances an incomplete request. The call waits for the archive step. If an archive already exists, it returns that same file without creating another one or sending the copies again. Otherwise it archives the signed PDF and attempts delivery to the signers. Archive availability does not prove email delivery. A null file_id is not permission to download the original as the signed result: re-read the request. Use [Get signing document](/developers/reference/signing/GetSigningDocument) with version=signed once the archive exists. BankID preserves the collected signed PDF; it is not re-rendered. Keep the same acting identity and grants used to access this signing request. ## Follow one signing request through completion [Upload a readable PDF](/developers/files), then [request signatures](/developers/reference/signing/RequestFileSignatures) and keep `signing_request_id`. The request keeps a fixed source; replacing the original file later does not change what recipients sign. Read [Get signing request](/developers/reference/signing/GetSigningRequest) for per-recipient progress. `completed` means everyone signed, but the archive can still be preparing: wait for non-null `file_id` before requesting the signed PDF. [Get signing document](/developers/reference/signing/GetSigningDocument) returns a short-lived URL for either the fixed original or the signed archive. Notification failures do not undo the signing request. Remind the affected pending recipients instead of creating a duplicate request. Recipients sign themselves; a delegated API call cannot supply a recipient's signature. See the [complete signing workflow](/developers/signing). ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `signing_request_id` | string | Yes | The same signing request, not a newly created session. | | `status` | string | Yes | completed confirms the signing session was complete. Use file_id, not status alone, to know whether an archive is available. | | `file_id` | string or null | Yes | Archived signed PDF identity. Use GetSigningDocument with version=signed to obtain a short-lived download URL. Null means no archive identity was returned; re-read GetSigningRequest before attempting a download. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `not_completed` | Every recipient must finish signing first. Read GetSigningRequest; this operation cannot supply their signatures. | | 502 | `url_scraper_failed` | Archive rendering failed. Read the signing request before retrying finalization; do not create another signing request. | ## Next steps - [Get signing request](/developers/reference/signing/GetSigningRequest) - [Get signing document](/developers/reference/signing/GetSigningDocument) - [List signing events](/developers/reference/signing/ListSigningEvents) - [Request file signatures](/developers/reference/signing/RequestFileSignatures) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### The signed archive is available A repeat returns the same archive. Download through GetSigningDocument, not a constructed storage URL. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/signing.FinalizeSigning' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "signing_request_id": "sig_project_agreement" }' ``` #### TypeScript ```typescript 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/signing.FinalizeSigning", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "signing_request_id": "sig_project_agreement" }), }); 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 = { "signing_request_id": "sig_project_agreement" } request = Request( "https://api.brigg.app/v1/operations/signing.FinalizeSigning", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "signing_request_id": "sig_project_agreement", "status": "completed", "file_id": "f_signed_agreement" } ``` ### No archive identity returned Read GetSigningRequest again; completed describes signatures and does not replace the file_id check. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/signing.FinalizeSigning' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "signing_request_id": "sig_project_agreement" }' ``` #### TypeScript ```typescript 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/signing.FinalizeSigning", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "signing_request_id": "sig_project_agreement" }), }); 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 = { "signing_request_id": "sig_project_agreement" } request = Request( "https://api.brigg.app/v1/operations/signing.FinalizeSigning", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "signing_request_id": "sig_project_agreement", "status": "completed", "file_id": null } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "signing_request_id": { "type": "string", "minLength": 1, "maxLength": 120, "description": "The signing_request_id returned when signatures were requested. Read GetSigningRequest first; every recipient must have signed." } }, "required": [ "signing_request_id" ], "additionalProperties": false, "examples": [ { "signing_request_id": "sig_project_agreement" } ] } ``` ```json-schema-response { "type": "object", "properties": { "signing_request_id": { "type": "string", "description": "The same signing request, not a newly created session." }, "status": { "type": "string", "description": "completed confirms the signing session was complete. Use file_id, not status alone, to know whether an archive is available." }, "file_id": { "type": [ "string", "null" ], "description": "Archived signed PDF identity. Use GetSigningDocument with version=signed to obtain a short-lived download URL. Null means no archive identity was returned; re-read GetSigningRequest before attempting a download." } }, "required": [ "signing_request_id", "status", "file_id" ], "additionalProperties": false, "examples": [ { "signing_request_id": "sig_project_agreement", "status": "completed", "file_id": "f_signed_agreement" } ] } ``` --- # Remind signers Send email reminders to pending signers and inspect the delivery outcome for each recipient. A recipient reminded within the last hour is skipped. SMS reminders require a person's own action in Brigg and are unavailable to API or agent calls. POST https://api.brigg.app/v1/operations/signing.RemindSigners ## Access & visibility Allow `signing.RemindSigners` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `signing_request_id` | string | Yes | Keep the signing_request_id returned when invitations were requested. A file_id or signer_id identifies something else. [signing.RequestFileSignatures](/developers/reference/signing/RequestFileSignatures). At least 1 character. At most 120 characters. | | `channels` | array of string | Yes | Use ["email"] for API and agent calls. Although sms is a protocol value, SMS reminders require the person's own action in Brigg and are refused for API keys, including delegated calls. Each item: `"email"`, `"sms"`. At least 1 item. At most 2 items. | | `signers` | array of [object](#request-signers) | No | Pending recipients to remind, using signer_id from signing.GetSigningRequest. Omit to remind all pending recipients. A supplied phone number is used only for this reminder's SMS; it does not change the recipient's saved number. At least 1 item. At most 50 items. | ### request.signers[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | signer_id from GetSigningRequest for this same signing_request_id. It is not a Person record ID or an email address. At least 1 character. | | `phone` | string | No | Reserved for a person's own SMS reminder in Brigg. Do not supply a phone number in API or agent calls; doing so returns sms_needs_person. At most 40 characters. | ## Send one reminder and inspect each outcome The signing request must still be pending and before its deadline. Use the same workspace credential that initiated a workspace request, or act as the member who initiated a personal request; a different member cannot send its reminders. Read [Get signing request](/developers/reference/signing/GetSigningRequest) first. Omit signers to target all pending recipients, or select their signer_id values. API calls support email reminders; SMS remains a person's action in Brigg. Member delegation does not turn an automated call into that human action. A 200 response can contain a mix of successful sends, failures and skipped recipients. A signer reminded within the last hour is skipped with retry_at. Retry a lost response with the original idempotency key; a later intentional reminder is a new action and needs a new key. Do not create a duplicate signing request to retry a notification. ## Follow one signing request through completion [Upload a readable PDF](/developers/files), then [request signatures](/developers/reference/signing/RequestFileSignatures) and keep `signing_request_id`. The request keeps a fixed source; replacing the original file later does not change what recipients sign. Read [Get signing request](/developers/reference/signing/GetSigningRequest) for per-recipient progress. `completed` means everyone signed, but the archive can still be preparing: wait for non-null `file_id` before requesting the signed PDF. [Get signing document](/developers/reference/signing/GetSigningDocument) returns a short-lived URL for either the fixed original or the signed archive. Notification failures do not undo the signing request. Remind the affected pending recipients instead of creating a duplicate request. Recipients sign themselves; a delegated API call cannot supply a recipient's signature. See the [complete signing workflow](/developers/signing). ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `signing_request_id` | string | Yes | Signing request identifier. | | `results` | array of [object](#response-results) | Yes | Per-recipient reminder delivery outcomes. | ### response.results[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `signer_id` | string | Yes | Signer identifier. | | `email` | string | Yes | Email address. | | `sent` | array of string | Yes | Channels on which the send succeeded, such as ["email"]. An empty array means no channel succeeded; inspect skipped and failures. This does not prove the recipient read the message. | | `failures` | array of [object](#response-results-failures) | Yes | Recipient notifications that could not be delivered. | | `skipped` | string | No | Reason no send was attempted: cooldown, not_pending or unknown_signer. This is an optional reason string, not a boolean. | | `retry_at` | number | No | For cooldown, the earliest time another deliberate reminder can be sent, in Unix milliseconds. Wait until then and use a new idempotency key for that new action. | ### response.results[].failures[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `channel` | string | Yes | Channel to use for the reminder, subject to the acting member's authority. | | `reason` | string | Yes | Delivery failure reported for this channel. A failed notification does not cancel the signing request; inspect the request before deciding to remind again. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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 | `sms_needs_person` | Use channels: [email] and omit phone. SMS requires the person's own action in Brigg; member delegation does not bypass this rule. | | 409 | `not_pending` | The signing request is completed or cancelled. Read its current state instead of sending another reminder. | | 410 | `expired` | The signing deadline has passed. The initiator must deliberately extend it before a reminder can be sent. | ## Next steps - [Get signing request](/developers/reference/signing/GetSigningRequest) - [Get signing document](/developers/reference/signing/GetSigningDocument) - [Send a document for signing](/developers/signing) - [Request file signatures](/developers/reference/signing/RequestFileSignatures) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Remind pending recipients One email succeeds and another recipient is still in the one-hour cooldown. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/signing.RemindSigners' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "signing_request_id": "sig_agreement", "channels": [ "email" ] }' ``` #### TypeScript ```typescript 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/signing.RemindSigners", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "signing_request_id": "sig_agreement", "channels": [ "email" ] }), }); 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 = { "signing_request_id": "sig_agreement", "channels": [ "email" ] } request = Request( "https://api.brigg.app/v1/operations/signing.RemindSigners", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "signing_request_id": "sig_agreement", "results": [ { "signer_id": "signer_jamie", "email": "jamie@example.com", "sent": [ "email" ], "failures": [] }, { "signer_id": "signer_alex", "email": "alex@example.com", "sent": [], "failures": [], "skipped": "cooldown", "retry_at": 1794304800000 } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "signing_request_id": { "type": "string", "minLength": 1, "maxLength": 120, "description": "Keep the signing_request_id returned when invitations were requested. A file_id or signer_id identifies something else. [signing.RequestFileSignatures](/developers/reference/signing/RequestFileSignatures)." }, "channels": { "type": "array", "items": { "type": "string", "enum": [ "email", "sms" ] }, "minItems": 1, "maxItems": 2, "description": "Use [\"email\"] for API and agent calls. Although sms is a protocol value, SMS reminders require the person's own action in Brigg and are refused for API keys, including delegated calls." }, "signers": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "signer_id from GetSigningRequest for this same signing_request_id. It is not a Person record ID or an email address." }, "phone": { "type": "string", "maxLength": 40, "description": "Reserved for a person's own SMS reminder in Brigg. Do not supply a phone number in API or agent calls; doing so returns sms_needs_person." } }, "required": [ "id" ], "additionalProperties": false }, "minItems": 1, "maxItems": 50, "description": "Pending recipients to remind, using signer_id from signing.GetSigningRequest. Omit to remind all pending recipients. A supplied phone number is used only for this reminder's SMS; it does not change the recipient's saved number." } }, "required": [ "signing_request_id", "channels" ], "additionalProperties": false, "examples": [ { "signing_request_id": "sig_agreement", "channels": [ "email" ] } ] } ``` ```json-schema-response { "type": "object", "properties": { "signing_request_id": { "type": "string", "description": "Signing request identifier." }, "results": { "type": "array", "items": { "type": "object", "properties": { "signer_id": { "type": "string", "description": "Signer identifier." }, "email": { "type": "string", "description": "Email address." }, "sent": { "type": "array", "items": { "type": "string" }, "description": "Channels on which the send succeeded, such as [\"email\"]. An empty array means no channel succeeded; inspect skipped and failures. This does not prove the recipient read the message." }, "failures": { "type": "array", "items": { "type": "object", "properties": { "channel": { "type": "string", "description": "Channel to use for the reminder, subject to the acting member's authority." }, "reason": { "type": "string", "description": "Delivery failure reported for this channel. A failed notification does not cancel the signing request; inspect the request before deciding to remind again." } }, "required": [ "channel", "reason" ], "additionalProperties": false }, "description": "Recipient notifications that could not be delivered." }, "skipped": { "type": "string", "description": "Reason no send was attempted: cooldown, not_pending or unknown_signer. This is an optional reason string, not a boolean." }, "retry_at": { "type": "number", "description": "For cooldown, the earliest time another deliberate reminder can be sent, in Unix milliseconds. Wait until then and use a new idempotency key for that new action." } }, "required": [ "signer_id", "email", "sent", "failures" ], "additionalProperties": false }, "description": "Per-recipient reminder delivery outcomes." } }, "required": [ "signing_request_id", "results" ], "additionalProperties": false, "examples": [ { "signing_request_id": "sig_agreement", "results": [ { "signer_id": "signer_jamie", "email": "jamie@example.com", "sent": [ "email" ], "failures": [] }, { "signer_id": "signer_alex", "email": "alex@example.com", "sent": [], "failures": [], "skipped": "cooldown", "retry_at": 1794304800000 } ] } ] } ``` --- # Request file signatures Send an uploaded PDF to named recipients for signature. Each recipient receives a private link and gives their own consent. Brigg preserves the original PDF and prepares a signed archive when everyone has signed. POST https://api.brigg.app/v1/operations/signing.RequestFileSignatures ## Access & visibility Allow `signing.RequestFileSignatures` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `file_id` | string | Yes | Use a file_id returned by this listing or by CompleteUpload. It is not an upload ID, storage path or filename. [documents.ListDocuments](/developers/reference/documents/ListDocuments). At least 1 character. | | `title` | string | Yes | Display title. At least 1 character. At most 200 characters. | | `signers` | array of [object](#request-signers) | Yes | Named recipients and their individual signature states. At least 1 item. | | `expires_at` | integer | No | Signing deadline in Unix milliseconds. | | `message` | string | No | Message sent to the signature recipients with their invitation. At most 2000 characters. | | `signature_method` | string | No | Signature method required for the request. Allowed: `"standard"`, `"bankid"`. Default: `"standard"`. | ### request.signers[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `email` | string | Yes | Email address. Format: email. | | `name` | string | No | The recipient's display name. Uses their account name or email when omitted. At most 120 characters. | ## Follow one signing request through completion [Upload a readable PDF](/developers/files), then [request signatures](/developers/reference/signing/RequestFileSignatures) and keep `signing_request_id`. The request keeps a fixed source; replacing the original file later does not change what recipients sign. Read [Get signing request](/developers/reference/signing/GetSigningRequest) for per-recipient progress. `completed` means everyone signed, but the archive can still be preparing: wait for non-null `file_id` before requesting the signed PDF. [Get signing document](/developers/reference/signing/GetSigningDocument) returns a short-lived URL for either the fixed original or the signed archive. Notification failures do not undo the signing request. Remind the affected pending recipients instead of creating a duplicate request. Recipients sign themselves; a delegated API call cannot supply a recipient's signature. See the [complete signing workflow](/developers/signing). ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `signing_request_id` | string | Yes | Signing request identifier. | | `status` | string | Yes | Current signing request or recipient state. A completed request may still be preparing its signed PDF. Allowed: `"pending"`. | | `invitation_failures` | array of string | Yes | Recipient email addresses whose invitation was not delivered. The request exists; use RemindSigners to retry delivery. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 422 | `pdf_required` | Upload a PDF before requesting signatures. | | 422 | `invalid_pdf` | Upload a readable PDF without password encryption. | | 402 | `insufficient_credits` | BankID requires sufficient workspace credit. Refill credit before retrying. | | 503 | `bankid_not_configured` | BankID is not configured for this environment. Use an available signing method or contact support. | ## Next steps - [Get signing request](/developers/reference/signing/GetSigningRequest) - [Get signing document](/developers/reference/signing/GetSigningDocument) - [Remind signers](/developers/reference/signing/RemindSigners) - [Send a document for signing](/developers/signing) - [List documents](/developers/reference/documents/ListDocuments) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/signing.RequestFileSignatures' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "file_id": "f_example", "title": "Consulting agreement", "signers": [ { "email": "alex@example.com", "name": "Alex Morgan" } ], "signature_method": "standard", "message": "Please review and sign our agreement." }' ``` #### TypeScript ```typescript 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/signing.RequestFileSignatures", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "file_id": "f_example", "title": "Consulting agreement", "signers": [ { "email": "alex@example.com", "name": "Alex Morgan" } ], "signature_method": "standard", "message": "Please review and sign our agreement." }), }); 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 = { "file_id": "f_example", "title": "Consulting agreement", "signers": [ { "email": "alex@example.com", "name": "Alex Morgan" } ], "signature_method": "standard", "message": "Please review and sign our agreement." } request = Request( "https://api.brigg.app/v1/operations/signing.RequestFileSignatures", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "signing_request_id": "sig_example", "status": "pending", "invitation_failures": [] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "file_id": { "type": "string", "minLength": 1, "description": "Use a file_id returned by this listing or by CompleteUpload. It is not an upload ID, storage path or filename. [documents.ListDocuments](/developers/reference/documents/ListDocuments)." }, "title": { "type": "string", "minLength": 1, "maxLength": 200, "description": "Display title." }, "signers": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email", "description": "Email address." }, "name": { "type": "string", "maxLength": 120, "description": "The recipient's display name. Uses their account name or email when omitted." } }, "required": [ "email" ], "additionalProperties": false }, "minItems": 1, "description": "Named recipients and their individual signature states." }, "expires_at": { "type": "integer", "description": "Signing deadline in Unix milliseconds." }, "message": { "type": "string", "maxLength": 2000, "description": "Message sent to the signature recipients with their invitation." }, "signature_method": { "type": "string", "enum": [ "standard", "bankid" ], "default": "standard", "description": "Signature method required for the request." } }, "required": [ "file_id", "title", "signers" ], "additionalProperties": false, "examples": [ { "file_id": "f_example", "title": "Consulting agreement", "signers": [ { "email": "alex@example.com", "name": "Alex Morgan" } ], "signature_method": "standard", "message": "Please review and sign our agreement." } ] } ``` ```json-schema-response { "type": "object", "properties": { "signing_request_id": { "type": "string", "description": "Signing request identifier." }, "status": { "type": "string", "enum": [ "pending" ], "description": "Current signing request or recipient state. A completed request may still be preparing its signed PDF." }, "invitation_failures": { "type": "array", "items": { "type": "string" }, "description": "Recipient email addresses whose invitation was not delivered. The request exists; use RemindSigners to retry delivery." } }, "required": [ "signing_request_id", "status", "invitation_failures" ], "additionalProperties": false, "examples": [ { "signing_request_id": "sig_example", "status": "pending", "invitation_failures": [] } ] } ``` --- # Set signing deadline Change a pending signing session's deadline and notify remaining signers. Existing links and signatures stay valid. An unchanged deadline sends no notifications. POST https://api.brigg.app/v1/operations/signing.SetSigningDeadline ## Access & visibility Allow `signing.SetSigningDeadline` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `signing_request_id` | string | Yes | Keep the signing_request_id returned when invitations were requested. A file_id or signer_id identifies something else. [signing.RequestFileSignatures](/developers/reference/signing/RequestFileSignatures). At least 1 character. At most 120 characters. | | `expires_at` | integer | Yes | New deadline in Unix milliseconds, in the future. Brigg presents the deadline as an inclusive date in Europe/Oslo; use the end of that local day (23:59:59.999), converted to an epoch timestamp. | ## Follow one signing request through completion [Upload a readable PDF](/developers/files), then [request signatures](/developers/reference/signing/RequestFileSignatures) and keep `signing_request_id`. The request keeps a fixed source; replacing the original file later does not change what recipients sign. Read [Get signing request](/developers/reference/signing/GetSigningRequest) for per-recipient progress. `completed` means everyone signed, but the archive can still be preparing: wait for non-null `file_id` before requesting the signed PDF. [Get signing document](/developers/reference/signing/GetSigningDocument) returns a short-lived URL for either the fixed original or the signed archive. Notification failures do not undo the signing request. Remind the affected pending recipients instead of creating a duplicate request. Recipients sign themselves; a delegated API call cannot supply a recipient's signature. See the [complete signing workflow](/developers/signing). ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `signing_request_id` | string | Yes | Signing request identifier. | | `expires_at` | number | Yes | Signing deadline in Unix milliseconds. | | `previous_expires_at` | number | Yes | Deadline before this update, in Unix milliseconds. | | `notified` | array of string | Yes | Whether remaining recipients were notified of the deadline change. | | `notice_failures` | array of string | Yes | Deadline-change notifications that could not be delivered. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [Get signing request](/developers/reference/signing/GetSigningRequest) - [Get signing document](/developers/reference/signing/GetSigningDocument) - [Remind signers](/developers/reference/signing/RemindSigners) - [Send a document for signing](/developers/signing) - [Request file signatures](/developers/reference/signing/RequestFileSignatures) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/signing.SetSigningDeadline' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "signing_request_id": "e_example", "expires_at": 1794301200000 }' ``` #### TypeScript ```typescript 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/signing.SetSigningDeadline", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "signing_request_id": "e_example", "expires_at": 1794301200000 }), }); 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 = { "signing_request_id": "e_example", "expires_at": 1794301200000 } request = Request( "https://api.brigg.app/v1/operations/signing.SetSigningDeadline", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "signing_request_id": "e_example", "expires_at": 1794301200000, "previous_expires_at": 1794301200000, "notified": [], "notice_failures": [] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "signing_request_id": { "type": "string", "minLength": 1, "maxLength": 120, "description": "Keep the signing_request_id returned when invitations were requested. A file_id or signer_id identifies something else. [signing.RequestFileSignatures](/developers/reference/signing/RequestFileSignatures)." }, "expires_at": { "type": "integer", "description": "New deadline in Unix milliseconds, in the future. Brigg presents the deadline as an inclusive date in Europe/Oslo; use the end of that local day (23:59:59.999), converted to an epoch timestamp." } }, "required": [ "signing_request_id", "expires_at" ], "additionalProperties": false, "examples": [ { "signing_request_id": "e_example", "expires_at": 1794301200000 } ] } ``` ```json-schema-response { "type": "object", "properties": { "signing_request_id": { "type": "string", "description": "Signing request identifier." }, "expires_at": { "type": "number", "description": "Signing deadline in Unix milliseconds." }, "previous_expires_at": { "type": "number", "description": "Deadline before this update, in Unix milliseconds." }, "notified": { "type": "array", "items": { "type": "string" }, "description": "Whether remaining recipients were notified of the deadline change." }, "notice_failures": { "type": "array", "items": { "type": "string" }, "description": "Deadline-change notifications that could not be delivered." } }, "required": [ "signing_request_id", "expires_at", "previous_expires_at", "notified", "notice_failures" ], "additionalProperties": false, "examples": [ { "signing_request_id": "e_example", "expires_at": 1794301200000, "previous_expires_at": 1794301200000, "notified": [], "notice_failures": [] } ] } ``` --- # Get task Read a task by ID. Returns item: null when no visible record matches. POST https://api.brigg.app/v1/operations/tasks.GetTask ## Access & visibility Allow `tasks.GetTask` on your API key. Resource read permissions: `core:Task`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:Task` record. Find it with [tasks.ListTasks](/developers/reference/tasks/ListTasks). Use the record's top-level `id`, not a business field or account ID. | ## Response Returns **200 OK** with a JSON body. `item: null` means there is no matching record visible to this caller. It does not reveal whether an inaccessible record exists. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [TaskRecord](#taskrecord-response-item) or null | Yes | null when no such record | ### TaskRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Task record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Task](#task-response-item-data) | Yes | The record's fields. | ### Task · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string | Yes | Short description of the work to complete. | | `status` | string | No | Work status: open, in_progress or done. A due date does not automatically change the status. Allowed: `"open"`, `"in_progress"`, `"done"`. | | `due_date` | string | No | Due date as YYYY-MM-DD, without a time zone or time of day. | | `assignee_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `description` | string | No | Details of the work to complete. | | `parent_type` | string | No | Record type this task belongs to, such as core:Company. | | `parent_id` | string | No | ID of the record identified by parent_type. | | `company_ref` | string | No | ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [List tasks](/developers/reference/tasks/ListTasks) - [Create task](/developers/reference/tasks/CreateTask) - [Upsert task](/developers/reference/tasks/UpsertTask) - [Update task](/developers/reference/tasks/UpdateTask) - [Delete task](/developers/reference/tasks/DeleteTask) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/tasks.GetTask' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "e_task_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/tasks.GetTask", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "id": "e_task_example" }), }); 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 payload = { "id": "e_task_example" } request = Request( "https://api.brigg.app/v1/operations/tasks.GetTask", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "item": { "id": "e_task_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "title": "Send project proposal", "status": "open", "due_date": "2026-11-13", "company_ref": "e_company_example", "description": "Prepare a proposal for the onboarding project." } } } ``` ### No visible record A missing or inaccessible record returns item: null. Do not treat this as proof that a record exists for another member. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/tasks.GetTask' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "id": "e_task_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/tasks.GetTask", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "id": "e_task_example" }), }); 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 payload = { "id": "e_task_example" } request = Request( "https://api.brigg.app/v1/operations/tasks.GetTask", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "item": null } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:Task` record. Find it with [tasks.ListTasks](/developers/reference/tasks/ListTasks). Use the record's top-level `id`, not a business field or account ID." } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_task_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": [ "object", "null" ], "properties": { "id": { "type": "string", "description": "Stable core:Task record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "title": { "type": "string", "description": "Short description of the work to complete." }, "status": { "type": "string", "enum": [ "open", "in_progress", "done" ], "description": "Work status: open, in_progress or done. A due date does not automatically change the status." }, "due_date": { "type": "string", "description": "Due date as YYYY-MM-DD, without a time zone or time of day." }, "assignee_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "description": { "type": "string", "description": "Details of the work to complete." }, "parent_type": { "type": "string", "description": "Record type this task belongs to, such as core:Company." }, "parent_id": { "type": "string", "description": "ID of the record identified by parent_type." }, "company_ref": { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." } }, "required": [ "title" ], "additionalProperties": false, "description": "The record's fields.", "title": "Task" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "null when no such record", "title": "TaskRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_task_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "title": "Send project proposal", "status": "open", "due_date": "2026-11-13", "company_ref": "e_company_example", "description": "Prepare a proposal for the onboarding project." } } } ] } ``` --- # List tasks List tasks visible to the credential, with filtering, sorting and cursor pagination. POST https://api.brigg.app/v1/operations/tasks.ListTasks ## Access & visibility Allow `tasks.ListTasks` on your API key. Resource read permissions: `core:Task`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `filters` | array of [object](#request-filters) | No | Conditions the row must ALL satisfy. | | `sort` | [object](#request-sort) | No | Sort order for the results. Defaults to updated_at descending, with id as a tie-breaker. | | `limit` | integer | No | Maximum number of results to return in this page. Continue with next_cursor when returned. Default: `100`. Minimum: 1. | | `cursor` | string | No | The `next_cursor` of the previous page. | ### request.filters[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | `data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private. Allowed: `"id"`, `"created_at"`, `"updated_at"`, `"created_by"`, `"private"`, `"data.title"`, `"data.status"`, `"data.due_date"`, `"data.assignee_ref"`, `"data.description"`, `"data.parent_type"`, `"data.parent_id"`, `"data.company_ref"`. | | `op` | string | Yes | Comparison operator. Use in with an array, or omit value for is_empty and is_not_empty. Allowed: `"eq"`, `"neq"`, `"contains"`, `"starts_with"`, `"gt"`, `"gte"`, `"lt"`, `"lte"`, `"in"`, `"has"`, `"is_empty"`, `"is_not_empty"`. | | `value` | JSON value | No | The comparison value; an array for `in`; omitted for is_empty / is_not_empty. | ### request.sort | Field | Type | Required | Description | | --- | --- | --- | --- | | `field` | string | Yes | `data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private. Allowed: `"id"`, `"created_at"`, `"updated_at"`, `"created_by"`, `"private"`, `"data.title"`, `"data.status"`, `"data.due_date"`, `"data.assignee_ref"`, `"data.description"`, `"data.parent_type"`, `"data.parent_id"`, `"data.company_ref"`. | | `direction` | string | No | Sort direction: asc for ascending or desc for descending. Allowed: `"asc"`, `"desc"`. | ## Filtering and sorting All conditions are combined with **AND**. Address business fields as `data.`, and record metadata as `id`, `created_at`, `updated_at`, `created_by` or `private`. A field path names one field; it does not traverse nested objects. | Operator | Meaning | Value | | --- | --- | --- | | `eq` | Equal to a scalar | String, number, boolean or null | | `neq` | Not equal; missing values also match | String, number, boolean or null | | `contains` | Case-insensitive text contains | String; % and _ are literal characters | | `starts_with` | Case-insensitive text prefix | String | | `gt`, `gte` | Greater than / at least | Number or string appropriate to the field | | `lt`, `lte` | Less than / at most | Number or string appropriate to the field | | `in` | Equal to any supplied scalar | Nonempty array of strings, numbers, booleans or null | | `has` | Array contains a string | One string; does not match properties inside array objects | | `is_empty` | Missing, null, empty string or empty array | Omit value | | `is_not_empty` | Has a nonempty value | Omit value | Match the stored field's type. Numeric business timestamps take Unix milliseconds; date-only business fields take `YYYY-MM-DD`. The record metadata fields `created_at` and `updated_at` also accept ISO timestamps for ordered comparisons. Sorting defaults to `updated_at` descending. If you supply `sort.field` without `sort.direction`, direction is `desc`. The record ID breaks ties; missing values sort last. ## Response Returns **200 OK** with a JSON body. An empty `items` array means this page contains no matching visible results. Follow `next_cursor` when present. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [TaskRecord](#taskrecord-response-items) | Yes | Records visible under the credential's grants and the selected data scope, matching the requested filters. Pass next_cursor as cursor to continue when a next cursor is returned. | | `next_cursor` | string | No | Pass this value as cursor to continue with the same filters, sort and credential. Omitted when there are no more results. | ### TaskRecord · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Task record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Task](#task-response-items-data) | Yes | The record's fields. | ### Task · response.items[].data | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string | Yes | Short description of the work to complete. | | `status` | string | No | Work status: open, in_progress or done. A due date does not automatically change the status. Allowed: `"open"`, `"in_progress"`, `"done"`. | | `due_date` | string | No | Due date as YYYY-MM-DD, without a time zone or time of day. | | `assignee_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `description` | string | No | Details of the work to complete. | | `parent_type` | string | No | Record type this task belongs to, such as core:Company. | | `parent_id` | string | No | ID of the record identified by parent_type. | | `company_ref` | string | No | ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name. | ## Pagination Pass `next_cursor` from the response as `cursor` on the next request. Keep the same filters, sort and acting identity. Stop when `next_cursor` is absent; do not infer completion from the number of items. The default page size is **100**; `limit` must be a positive integer. **Pagination is a live view, not a snapshot.** Changes between pages can move records across page boundaries. Upsert by record ID rather than appending blindly. For recurring synchronization, use an overlapping update window and deduplicate records. Periodically reconcile IDs to detect deletions. [Resource webhooks](/developers/webhooks) can supplement synchronization for eligible workspace-shared records only: they do not export private or project-scoped records. Personal data still needs polling and reconciliation. ```typescript const query = { "limit": 10 }; let cursor; do { const response = await fetch("https://api.brigg.app/v1/operations/tasks.ListTasks", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ ...query, ...(cursor ? { cursor } : {}) }), }); const page = await response.json(); if (!response.ok) throw new Error(`${response.status}: ${page.message}`); for (const item of page.items) { console.log(item); // Process or upsert each result. } cursor = page.next_cursor; } while (cursor); ``` ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | | 400 | `cursor_invalid` | Restart pagination with no cursor. | | 400 | `cursor_mismatch` | Use the cursor with the original filters, sort order and credential. | ## Next steps - [Get task](/developers/reference/tasks/GetTask) - [Create task](/developers/reference/tasks/CreateTask) - [Upsert task](/developers/reference/tasks/UpsertTask) - [Update task](/developers/reference/tasks/UpdateTask) - [Delete task](/developers/reference/tasks/DeleteTask) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### First page Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/tasks.ListTasks' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "limit": 10 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/tasks.ListTasks", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "limit": 10 }), }); 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 payload = { "limit": 10 } request = Request( "https://api.brigg.app/v1/operations/tasks.ListTasks", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_task_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "title": "Send project proposal", "status": "open", "due_date": "2026-11-13", "company_ref": "e_company_example", "description": "Prepare a proposal for the onboarding project." } } ] } ``` ### Overdue unfinished work Date-only due dates use YYYY-MM-DD. Replace the cutoff with today's date; a due date alone never marks a task done. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/tasks.ListTasks' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "limit": 50, "filters": [ { "field": "data.status", "op": "in", "value": [ "open", "in_progress" ] }, { "field": "data.due_date", "op": "lt", "value": "2026-11-10" } ], "sort": { "field": "data.due_date", "direction": "asc" } }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/tasks.ListTasks", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "limit": 50, "filters": [ { "field": "data.status", "op": "in", "value": [ "open", "in_progress" ] }, { "field": "data.due_date", "op": "lt", "value": "2026-11-10" } ], "sort": { "field": "data.due_date", "direction": "asc" } }), }); 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 payload = { "limit": 50, "filters": [ { "field": "data.status", "op": "in", "value": [ "open", "in_progress" ] }, { "field": "data.due_date", "op": "lt", "value": "2026-11-10" } ], "sort": { "field": "data.due_date", "direction": "asc" } } request = Request( "https://api.brigg.app/v1/operations/tasks.ListTasks", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_task_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "title": "Send project proposal", "status": "open", "due_date": "2026-11-09", "company_ref": "e_company_example", "description": "Prepare a proposal for the onboarding project." } } ] } ``` ### Records updated since a checkpoint 6 October 2026 at 00:00 UTC. Use an overlap window and upsert by ID when synchronizing. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/tasks.ListTasks' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/tasks.ListTasks", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 }), }); 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 payload = { "filters": [ { "field": "updated_at", "op": "gte", "value": 1791244800000 } ], "sort": { "field": "updated_at", "direction": "asc" }, "limit": 100 } request = Request( "https://api.brigg.app/v1/operations/tasks.ListTasks", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "e_task_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "title": "Send project proposal", "status": "open", "due_date": "2026-11-13", "company_ref": "e_company_example", "description": "Prepare a proposal for the onboarding project." } } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "filters": { "type": "array", "items": { "type": "object", "properties": { "field": { "type": "string", "description": "`data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private.", "enum": [ "id", "created_at", "updated_at", "created_by", "private", "data.title", "data.status", "data.due_date", "data.assignee_ref", "data.description", "data.parent_type", "data.parent_id", "data.company_ref" ] }, "op": { "type": "string", "enum": [ "eq", "neq", "contains", "starts_with", "gt", "gte", "lt", "lte", "in", "has", "is_empty", "is_not_empty" ], "description": "Comparison operator. Use in with an array, or omit value for is_empty and is_not_empty." }, "value": { "description": "The comparison value; an array for `in`; omitted for is_empty / is_not_empty." } }, "required": [ "field", "op" ], "additionalProperties": false }, "description": "Conditions the row must ALL satisfy." }, "sort": { "type": "object", "properties": { "field": { "type": "string", "description": "`data.` for a field of the record, or one of its own id, created_at, updated_at, created_by, private.", "enum": [ "id", "created_at", "updated_at", "created_by", "private", "data.title", "data.status", "data.due_date", "data.assignee_ref", "data.description", "data.parent_type", "data.parent_id", "data.company_ref" ] }, "direction": { "type": "string", "enum": [ "asc", "desc" ], "description": "Sort direction: asc for ascending or desc for descending." } }, "required": [ "field" ], "additionalProperties": false, "description": "Sort order for the results. Defaults to updated_at descending, with id as a tie-breaker." }, "limit": { "type": "integer", "minimum": 1, "default": 100, "description": "Maximum number of results to return in this page. Continue with next_cursor when returned." }, "cursor": { "type": "string", "description": "The `next_cursor` of the previous page." } }, "additionalProperties": false, "examples": [ { "limit": 10 } ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:Task record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "title": { "type": "string", "description": "Short description of the work to complete." }, "status": { "type": "string", "enum": [ "open", "in_progress", "done" ], "description": "Work status: open, in_progress or done. A due date does not automatically change the status." }, "due_date": { "type": "string", "description": "Due date as YYYY-MM-DD, without a time zone or time of day." }, "assignee_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "description": { "type": "string", "description": "Details of the work to complete." }, "parent_type": { "type": "string", "description": "Record type this task belongs to, such as core:Company." }, "parent_id": { "type": "string", "description": "ID of the record identified by parent_type." }, "company_ref": { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." } }, "required": [ "title" ], "additionalProperties": false, "description": "The record's fields.", "title": "Task" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "title": "TaskRecord" }, "description": "Records visible under the credential's grants and the selected data scope, matching the requested filters. Pass next_cursor as cursor to continue when a next cursor is returned." }, "next_cursor": { "type": "string", "description": "Pass this value as cursor to continue with the same filters, sort and credential. Omitted when there are no more results." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "id": "e_task_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "title": "Send project proposal", "status": "open", "due_date": "2026-11-13", "company_ref": "e_company_example", "description": "Prepare a proposal for the onboarding project." } } ] } ] } ``` --- # Create task Create a task and return the saved record. POST https://api.brigg.app/v1/operations/tasks.CreateTask ## Access & visibility Allow `tasks.CreateTask` on your API key. Resource read permissions: `core:Task`. Resource write permissions: `core:Task`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `data` | [Task](#task-request-data) | Yes | The record's fields. | | `private` | boolean | No | Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance. | ### Task · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string | Yes | Short description of the work to complete. | | `status` | string | No | Work status: open, in_progress or done. A due date does not automatically change the status. Allowed: `"open"`, `"in_progress"`, `"done"`. | | `due_date` | string | No | Due date as YYYY-MM-DD, without a time zone or time of day. | | `assignee_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `description` | string | No | Details of the work to complete. | | `parent_type` | string | No | Record type this task belongs to, such as core:Company. | | `parent_id` | string | No | ID of the record identified by parent_type. | | `company_ref` | string | No | ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name. | ## Choose ownership deliberately Omitting `private`, or setting it to false, creates a workspace-shared record. Set `private: true` to create a record owned by the approved acting member. Private records require member delegation; a workspace-only credential cannot own a personal record. The credential’s exact resource grants authorize the write; private ownership and project membership remain enforced. A create is a new record, not an upsert. Reuse the same idempotency key only for retries of that logical creation. For recurring synchronization, use the resource’s upsert operation when available: it matches a permanent external reference. Otherwise keep the returned record ID and use the corresponding update operation for subsequent changes. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [TaskRecord](#taskrecord-response-item) | Yes | The requested record, including its metadata and data fields. | ### TaskRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Task record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Task](#task-response-item-data) | Yes | The record's fields. | ### Task · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string | Yes | Short description of the work to complete. | | `status` | string | No | Work status: open, in_progress or done. A due date does not automatically change the status. Allowed: `"open"`, `"in_progress"`, `"done"`. | | `due_date` | string | No | Due date as YYYY-MM-DD, without a time zone or time of day. | | `assignee_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `description` | string | No | Details of the work to complete. | | `parent_type` | string | No | Record type this task belongs to, such as core:Company. | | `parent_id` | string | No | ID of the record identified by parent_type. | | `company_ref` | string | No | ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List tasks](/developers/reference/tasks/ListTasks) - [Get task](/developers/reference/tasks/GetTask) - [Upsert task](/developers/reference/tasks/UpsertTask) - [Update task](/developers/reference/tasks/UpdateTask) - [Delete task](/developers/reference/tasks/DeleteTask) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/tasks.CreateTask' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "data": { "title": "Send project proposal", "status": "open", "due_date": "2026-11-13", "company_ref": "e_company_example", "description": "Prepare a proposal for the onboarding project." } }' ``` #### TypeScript ```typescript 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/tasks.CreateTask", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "data": { "title": "Send project proposal", "status": "open", "due_date": "2026-11-13", "company_ref": "e_company_example", "description": "Prepare a proposal for the onboarding project." } }), }); 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 = { "data": { "title": "Send project proposal", "status": "open", "due_date": "2026-11-13", "company_ref": "e_company_example", "description": "Prepare a proposal for the onboarding project." } } request = Request( "https://api.brigg.app/v1/operations/tasks.CreateTask", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_task_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "title": "Send project proposal", "status": "open", "due_date": "2026-11-13", "company_ref": "e_company_example", "description": "Prepare a proposal for the onboarding project." } } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "data": { "type": "object", "properties": { "title": { "type": "string", "description": "Short description of the work to complete." }, "status": { "type": "string", "enum": [ "open", "in_progress", "done" ], "description": "Work status: open, in_progress or done. A due date does not automatically change the status." }, "due_date": { "type": "string", "description": "Due date as YYYY-MM-DD, without a time zone or time of day." }, "assignee_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "description": { "type": "string", "description": "Details of the work to complete." }, "parent_type": { "type": "string", "description": "Record type this task belongs to, such as core:Company." }, "parent_id": { "type": "string", "description": "ID of the record identified by parent_type." }, "company_ref": { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." } }, "required": [ "title" ], "additionalProperties": false, "description": "The record's fields.", "title": "Task" }, "private": { "type": "boolean", "description": "Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance." } }, "required": [ "data" ], "additionalProperties": false, "examples": [ { "data": { "title": "Send project proposal", "status": "open", "due_date": "2026-11-13", "company_ref": "e_company_example", "description": "Prepare a proposal for the onboarding project." } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:Task record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "title": { "type": "string", "description": "Short description of the work to complete." }, "status": { "type": "string", "enum": [ "open", "in_progress", "done" ], "description": "Work status: open, in_progress or done. A due date does not automatically change the status." }, "due_date": { "type": "string", "description": "Due date as YYYY-MM-DD, without a time zone or time of day." }, "assignee_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "description": { "type": "string", "description": "Details of the work to complete." }, "parent_type": { "type": "string", "description": "Record type this task belongs to, such as core:Company." }, "parent_id": { "type": "string", "description": "ID of the record identified by parent_type." }, "company_ref": { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." } }, "required": [ "title" ], "additionalProperties": false, "description": "The record's fields.", "title": "Task" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "TaskRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_task_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "title": "Send project proposal", "status": "open", "due_date": "2026-11-13", "company_ref": "e_company_example", "description": "Prepare a proposal for the onboarding project." } } } ] } ``` --- # Delete task Delete a task by ID. Repeating a deletion returns already_deleted. POST https://api.brigg.app/v1/operations/tasks.DeleteTask ## Access & visibility Allow `tasks.DeleteTask` on your API key. Resource read permissions: `core:Task`. Resource write permissions: `core:Task`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:Task` record. Find it with [tasks.ListTasks](/developers/reference/tasks/ListTasks). Use the record's top-level `id`, not a business field or account ID. | | `expected` | [object](#request-expected) | No | Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {"$absent":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource. | ### request.expected | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string or [object](#request-expected-title) | No | Commit only if the previous title value matches; use $absent to require that this field is missing. | | `status` | string or [object](#request-expected-status) | No | Commit only if the previous status value matches; use $absent to require that this field is missing. | | `due_date` | string or [object](#request-expected-due-date) | No | Commit only if the previous due_date value matches; use $absent to require that this field is missing. | | `assignee_ref` | string or [object](#request-expected-assignee-ref) | No | Commit only if the previous assignee_ref value matches; use $absent to require that this field is missing. | | `description` | string or [object](#request-expected-description) | No | Commit only if the previous description value matches; use $absent to require that this field is missing. | | `parent_type` | string or [object](#request-expected-parent-type) | No | Commit only if the previous parent_type value matches; use $absent to require that this field is missing. | | `parent_id` | string or [object](#request-expected-parent-id) | No | Commit only if the previous parent_id value matches; use $absent to require that this field is missing. | | `company_ref` | string or [object](#request-expected-company-ref) | No | Commit only if the previous company_ref value matches; use $absent to require that this field is missing. | ### request.expected.title | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.status | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.due_date | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.assignee_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.description | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.parent_type | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.parent_id | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.company_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ## Deletion and retries A successful response reports whether this call removed the record or it was already absent. Check `cascaded` for dependent record IDs returned by the operation. Retrying the same action uses the original idempotency key. A successful deletion is not an archive you can restore through this operation. To avoid deleting a record someone has changed, read it first and put the relevant prior business values in `expected`. Keys are relative to `data`, not prefixed with `data.`. Use {"$absent": true} to require a missing field. A mismatch returns 409 conflict; read again and decide whether deletion is still appropriate. A revised action needs a new idempotency key. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `deleted` | string | Yes | deleted when this request removed the record; already_deleted when it was already absent. Allowed: `"deleted"`, `"already_deleted"`. | | `cascaded` | array of string | No | IDs of dependent records deleted with this 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `conflict` | A supplied expected value no longer matches. Read the record again before deciding whether to retry. | ## Next steps - [List tasks](/developers/reference/tasks/ListTasks) - [Get task](/developers/reference/tasks/GetTask) - [Create task](/developers/reference/tasks/CreateTask) - [Upsert task](/developers/reference/tasks/UpsertTask) - [Update task](/developers/reference/tasks/UpdateTask) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/tasks.DeleteTask' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_task_example" }' ``` #### TypeScript ```typescript 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/tasks.DeleteTask", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_task_example" }), }); 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_task_example" } request = Request( "https://api.brigg.app/v1/operations/tasks.DeleteTask", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "deleted": "deleted" } ``` ### Delete only if unchanged Use a value you actually read. A concurrent change refuses the write with 409 conflict. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/tasks.DeleteTask' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_task_example", "expected": { "title": "Send project proposal" } }' ``` #### TypeScript ```typescript 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/tasks.DeleteTask", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_task_example", "expected": { "title": "Send project proposal" } }), }); 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_task_example", "expected": { "title": "Send project proposal" } } request = Request( "https://api.brigg.app/v1/operations/tasks.DeleteTask", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "deleted": "deleted" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:Task` record. Find it with [tasks.ListTasks](/developers/reference/tasks/ListTasks). Use the record's top-level `id`, not a business field or account ID." }, "expected": { "type": "object", "description": "Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {\"$absent\":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource.", "additionalProperties": false, "properties": { "title": { "description": "Commit only if the previous title value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Short description of the work to complete." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "status": { "description": "Commit only if the previous status value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "enum": [ "open", "in_progress", "done" ], "description": "Work status: open, in_progress or done. A due date does not automatically change the status." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "due_date": { "description": "Commit only if the previous due_date value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Due date as YYYY-MM-DD, without a time zone or time of day." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "assignee_ref": { "description": "Commit only if the previous assignee_ref value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "description": { "description": "Commit only if the previous description value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Details of the work to complete." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "parent_type": { "description": "Commit only if the previous parent_type value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Record type this task belongs to, such as core:Company." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "parent_id": { "description": "Commit only if the previous parent_id value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "ID of the record identified by parent_type." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "company_ref": { "description": "Commit only if the previous company_ref value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] } } } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_task_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "deleted": { "type": "string", "enum": [ "deleted", "already_deleted" ], "description": "deleted when this request removed the record; already_deleted when it was already absent." }, "cascaded": { "type": "array", "items": { "type": "string" }, "description": "IDs of dependent records deleted with this record." } }, "required": [ "deleted" ], "additionalProperties": false, "examples": [ { "deleted": "deleted" } ] } ``` --- # Update task Update a task by ID. Omitted fields stay unchanged; use unset to remove fields and expected to prevent overwriting a concurrent change. POST https://api.brigg.app/v1/operations/tasks.UpdateTask ## Access & visibility Allow `tasks.UpdateTask` on your API key. Resource read permissions: `core:Task`. Resource write permissions: `core:Task`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | ID of a visible `core:Task` record. Find it with [tasks.ListTasks](/developers/reference/tasks/ListTasks). Use the record's top-level `id`, not a business field or account ID. | | `data` | [Task](#task-request-data) | No | The fields to set. | | `unset` | array of string | No | Keys of `data` to remove. Each item: `"title"`, `"status"`, `"due_date"`, `"assignee_ref"`, `"description"`, `"parent_type"`, `"parent_id"`, `"company_ref"`. | | `expected` | [object](#request-expected) | No | Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {"$absent":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource. | ### Task · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string | No | Short description of the work to complete. | | `status` | string | No | Work status: open, in_progress or done. A due date does not automatically change the status. Allowed: `"open"`, `"in_progress"`, `"done"`. | | `due_date` | string | No | Due date as YYYY-MM-DD, without a time zone or time of day. | | `assignee_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `description` | string | No | Details of the work to complete. | | `parent_type` | string | No | Record type this task belongs to, such as core:Company. | | `parent_id` | string | No | ID of the record identified by parent_type. | | `company_ref` | string | No | ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name. | ### request.expected | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string or [object](#request-expected-title) | No | Commit only if the previous title value matches; use $absent to require that this field is missing. | | `status` | string or [object](#request-expected-status) | No | Commit only if the previous status value matches; use $absent to require that this field is missing. | | `due_date` | string or [object](#request-expected-due-date) | No | Commit only if the previous due_date value matches; use $absent to require that this field is missing. | | `assignee_ref` | string or [object](#request-expected-assignee-ref) | No | Commit only if the previous assignee_ref value matches; use $absent to require that this field is missing. | | `description` | string or [object](#request-expected-description) | No | Commit only if the previous description value matches; use $absent to require that this field is missing. | | `parent_type` | string or [object](#request-expected-parent-type) | No | Commit only if the previous parent_type value matches; use $absent to require that this field is missing. | | `parent_id` | string or [object](#request-expected-parent-id) | No | Commit only if the previous parent_id value matches; use $absent to require that this field is missing. | | `company_ref` | string or [object](#request-expected-company-ref) | No | Commit only if the previous company_ref value matches; use $absent to require that this field is missing. | ### request.expected.title | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.status | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.due_date | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.assignee_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.description | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.parent_type | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.parent_id | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ### request.expected.company_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `$absent` | boolean | Yes | Require the field to be missing, rather than present with a null value. Always `true`. | ## Update without losing changes Send only the business fields you want to change in `data`; omitted fields stay unchanged. Use `unset` to remove an optional field. Setting a field to null is a different action and is allowed only when its schema permits null. Use `expected` for a conditional update: supply the values you last read for the fields whose concurrent changes would matter. `{"$absent": true}` expects a missing field. A conflict means you must read the record again and decide how to reconcile the change. Keep the same idempotency key when retrying the original action; use a new key for a revised action. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [TaskRecord](#taskrecord-response-item) | Yes | The requested record, including its metadata and data fields. | ### TaskRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Task record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Task](#task-response-item-data) | Yes | The record's fields. | ### Task · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string | Yes | Short description of the work to complete. | | `status` | string | No | Work status: open, in_progress or done. A due date does not automatically change the status. Allowed: `"open"`, `"in_progress"`, `"done"`. | | `due_date` | string | No | Due date as YYYY-MM-DD, without a time zone or time of day. | | `assignee_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `description` | string | No | Details of the work to complete. | | `parent_type` | string | No | Record type this task belongs to, such as core:Company. | | `parent_id` | string | No | ID of the record identified by parent_type. | | `company_ref` | string | No | ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 409 | `conflict` | A supplied expected value no longer matches. Read the record again before deciding whether to retry. | ## Next steps - [List tasks](/developers/reference/tasks/ListTasks) - [Get task](/developers/reference/tasks/GetTask) - [Create task](/developers/reference/tasks/CreateTask) - [Upsert task](/developers/reference/tasks/UpsertTask) - [Delete task](/developers/reference/tasks/DeleteTask) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/tasks.UpdateTask' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_task_example", "data": { "status": "done" } }' ``` #### TypeScript ```typescript 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/tasks.UpdateTask", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_task_example", "data": { "status": "done" } }), }); 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_task_example", "data": { "status": "done" } } request = Request( "https://api.brigg.app/v1/operations/tasks.UpdateTask", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_task_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "title": "Send project proposal", "status": "done", "due_date": "2026-11-13", "company_ref": "e_company_example", "description": "Prepare a proposal for the onboarding project." } } } ``` ### Update only if unchanged Use a value you actually read. A concurrent change refuses the write with 409 conflict. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/tasks.UpdateTask' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_task_example", "data": { "status": "done" }, "expected": { "title": "Send project proposal" } }' ``` #### TypeScript ```typescript 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/tasks.UpdateTask", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_task_example", "data": { "status": "done" }, "expected": { "title": "Send project proposal" } }), }); 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_task_example", "data": { "status": "done" }, "expected": { "title": "Send project proposal" } } request = Request( "https://api.brigg.app/v1/operations/tasks.UpdateTask", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_task_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "title": "Send project proposal", "status": "done", "due_date": "2026-11-13", "company_ref": "e_company_example", "description": "Prepare a proposal for the onboarding project." } } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "description": "ID of a visible `core:Task` record. Find it with [tasks.ListTasks](/developers/reference/tasks/ListTasks). Use the record's top-level `id`, not a business field or account ID." }, "data": { "type": "object", "properties": { "title": { "type": "string", "description": "Short description of the work to complete." }, "status": { "type": "string", "enum": [ "open", "in_progress", "done" ], "description": "Work status: open, in_progress or done. A due date does not automatically change the status." }, "due_date": { "type": "string", "description": "Due date as YYYY-MM-DD, without a time zone or time of day." }, "assignee_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "description": { "type": "string", "description": "Details of the work to complete." }, "parent_type": { "type": "string", "description": "Record type this task belongs to, such as core:Company." }, "parent_id": { "type": "string", "description": "ID of the record identified by parent_type." }, "company_ref": { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." } }, "required": [], "additionalProperties": false, "description": "The fields to set.", "title": "Task" }, "unset": { "type": "array", "items": { "type": "string", "enum": [ "title", "status", "due_date", "assignee_ref", "description", "parent_type", "parent_id", "company_ref" ] }, "description": "Keys of `data` to remove." }, "expected": { "type": "object", "description": "Prior business-field values that must still match before the write. Use fields from this record’s data object, without the data. prefix. Use {\"$absent\":true} as a value to require an absent field. A mismatch returns 409 conflict. See the conditional example for this resource.", "additionalProperties": false, "properties": { "title": { "description": "Commit only if the previous title value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Short description of the work to complete." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "status": { "description": "Commit only if the previous status value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "enum": [ "open", "in_progress", "done" ], "description": "Work status: open, in_progress or done. A due date does not automatically change the status." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "due_date": { "description": "Commit only if the previous due_date value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Due date as YYYY-MM-DD, without a time zone or time of day." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "assignee_ref": { "description": "Commit only if the previous assignee_ref value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "description": { "description": "Commit only if the previous description value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Details of the work to complete." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "parent_type": { "description": "Commit only if the previous parent_type value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "Record type this task belongs to, such as core:Company." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "parent_id": { "description": "Commit only if the previous parent_id value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "ID of the record identified by parent_type." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] }, "company_ref": { "description": "Commit only if the previous company_ref value matches; use $absent to require that this field is missing.", "anyOf": [ { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." }, { "type": "object", "properties": { "$absent": { "type": "boolean", "const": true, "description": "Require the field to be missing, rather than present with a null value." } }, "required": [ "$absent" ], "additionalProperties": false } ] } } } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_task_example", "data": { "status": "done" } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:Task record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "title": { "type": "string", "description": "Short description of the work to complete." }, "status": { "type": "string", "enum": [ "open", "in_progress", "done" ], "description": "Work status: open, in_progress or done. A due date does not automatically change the status." }, "due_date": { "type": "string", "description": "Due date as YYYY-MM-DD, without a time zone or time of day." }, "assignee_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "description": { "type": "string", "description": "Details of the work to complete." }, "parent_type": { "type": "string", "description": "Record type this task belongs to, such as core:Company." }, "parent_id": { "type": "string", "description": "ID of the record identified by parent_type." }, "company_ref": { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." } }, "required": [ "title" ], "additionalProperties": false, "description": "The record's fields.", "title": "Task" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "TaskRecord" } }, "required": [ "item" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_task_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "title": "Send project proposal", "status": "done", "due_date": "2026-11-13", "company_ref": "e_company_example", "description": "Prepare a proposal for the onboarding project." } } } ] } ``` --- # Upsert task Create or update a task by a permanent external reference. Matching is exact within the workspace, resource type and ownership scope. Supplied fields replace their values; omitted fields stay unchanged. Deleted records are not recreated. POST https://api.brigg.app/v1/operations/tasks.UpsertTask ## Access & visibility Allow `tasks.UpsertTask` on your API key. Resource read permissions: `core:Task`. Resource write permissions: `core:Task`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `data` | [Task](#task-request-data) | Yes | The record's fields. | | `private` | boolean | No | Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance. | | `external_ref` | [object](#request-external-ref) | Yes | Permanent, case-sensitive source identity within this workspace, resource type and private/workspace scope. It is independent of API key rotation and retry receipt expiry. | ### Task · request.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string | Yes | Short description of the work to complete. | | `status` | string | No | Work status: open, in_progress or done. A due date does not automatically change the status. Allowed: `"open"`, `"in_progress"`, `"done"`. | | `due_date` | string | No | Due date as YYYY-MM-DD, without a time zone or time of day. | | `assignee_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `description` | string | No | Details of the work to complete. | | `parent_type` | string | No | Record type this task belongs to, such as core:Company. | | `parent_id` | string | No | ID of the record identified by parent_type. | | `company_ref` | string | No | ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name. | ### request.external_ref | Field | Type | Required | Description | | --- | --- | --- | --- | | `namespace` | string | Yes | A stable name for the source system, such as crm-production. At least 1 character. | | `id` | string | Yes | The record ID in that source system. At least 1 character. | ## Sync with a permanent external reference Choose a stable `external_ref.namespace` for your source system and put its record ID in `external_ref.id`. Matching is case-sensitive and scoped to this workspace, resource type and private/workspace ownership. The reference survives API key replacement and the 30-day retry receipt window. It does not match records by email or name. Send the required create fields each time. A missing reference creates a record; an existing reference updates only supplied fields and preserves everything else. `created` tells you which happened. Use the same idempotency key when retrying a lost response and a new key for a later source change. Concurrent calls cannot create duplicate records. A deleted or inaccessible match is refused; the operation does not restore it or make a replacement. Use the returned `item.id` with the regular update operation when you need `unset` or a conditional `expected` edit. Changing `private` chooses a different ownership scope; it does not transfer an existing record. ## Response Returns **200 OK** with a JSON body. Record metadata sits outside `data`. Timestamps `created_at` and `updated_at` are Unix milliseconds. Optional business fields may be absent; absence does not mean false or zero. A field accepts null only when its type includes null. | Field | Type | Required | Description | | --- | --- | --- | --- | | `item` | [TaskRecord](#taskrecord-response-item) | Yes | The requested record, including its metadata and data fields. | | `created` | boolean | Yes | True when this external reference created a record; false when it matched an existing record. | ### TaskRecord · response.item | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Stable core:Task record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited. | | `created_at` | number | Yes | Time the record was created, in Unix milliseconds. | | `updated_at` | number | Yes | Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads. | | `created_by` | string or null | Yes | Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID. | | `private` | boolean | Yes | True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules. | | `data` | [Task](#task-response-item-data) | Yes | The record's fields. | ### Task · response.item.data | Field | Type | Required | Description | | --- | --- | --- | --- | | `title` | string | Yes | Short description of the work to complete. | | `status` | string | No | Work status: open, in_progress or done. A due date does not automatically change the status. Allowed: `"open"`, `"in_progress"`, `"done"`. | | `due_date` | string | No | Due date as YYYY-MM-DD, without a time zone or time of day. | | `assignee_ref` | string | No | ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name. | | `description` | string | No | Details of the work to complete. | | `parent_type` | string | No | Record type this task belongs to, such as core:Company. | | `parent_id` | string | No | ID of the record identified by parent_type. | | `company_ref` | string | No | ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List tasks](/developers/reference/tasks/ListTasks) - [Get task](/developers/reference/tasks/GetTask) - [Create task](/developers/reference/tasks/CreateTask) - [Update task](/developers/reference/tasks/UpdateTask) - [Delete task](/developers/reference/tasks/DeleteTask) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### First sync Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/tasks.UpsertTask' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "title": "Send project proposal", "status": "open", "due_date": "2026-11-13", "company_ref": "e_company_example", "description": "Prepare a proposal for the onboarding project." } }' ``` #### TypeScript ```typescript 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/tasks.UpsertTask", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "title": "Send project proposal", "status": "open", "due_date": "2026-11-13", "company_ref": "e_company_example", "description": "Prepare a proposal for the onboarding project." } }), }); 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 = { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "title": "Send project proposal", "status": "open", "due_date": "2026-11-13", "company_ref": "e_company_example", "description": "Prepare a proposal for the onboarding project." } } request = Request( "https://api.brigg.app/v1/operations/tasks.UpsertTask", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_task_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "title": "Send project proposal", "status": "open", "due_date": "2026-11-13", "company_ref": "e_company_example", "description": "Prepare a proposal for the onboarding project." } }, "created": true } ``` ### Later sync The same external reference returns the same record ID. Use a new idempotency key for a later source change. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/tasks.UpsertTask' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "title": "Send project proposal", "status": "open", "due_date": "2026-11-13", "company_ref": "e_company_example", "description": "Prepare a proposal for the onboarding project." } }' ``` #### TypeScript ```typescript 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/tasks.UpsertTask", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "title": "Send project proposal", "status": "open", "due_date": "2026-11-13", "company_ref": "e_company_example", "description": "Prepare a proposal for the onboarding project." } }), }); 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 = { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "title": "Send project proposal", "status": "open", "due_date": "2026-11-13", "company_ref": "e_company_example", "description": "Prepare a proposal for the onboarding project." } } request = Request( "https://api.brigg.app/v1/operations/tasks.UpsertTask", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "item": { "id": "e_task_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "title": "Send project proposal", "status": "open", "due_date": "2026-11-13", "company_ref": "e_company_example", "description": "Prepare a proposal for the onboarding project." } }, "created": false } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "data": { "type": "object", "properties": { "title": { "type": "string", "description": "Short description of the work to complete." }, "status": { "type": "string", "enum": [ "open", "in_progress", "done" ], "description": "Work status: open, in_progress or done. A due date does not automatically change the status." }, "due_date": { "type": "string", "description": "Due date as YYYY-MM-DD, without a time zone or time of day." }, "assignee_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "description": { "type": "string", "description": "Details of the work to complete." }, "parent_type": { "type": "string", "description": "Record type this task belongs to, such as core:Company." }, "parent_id": { "type": "string", "description": "ID of the record identified by parent_type." }, "company_ref": { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." } }, "required": [ "title" ], "additionalProperties": false, "description": "The record's fields.", "title": "Task" }, "private": { "type": "boolean", "description": "Defaults to false: the record is shared with the workspace. True assigns private ownership to the approved acting member and requires member delegation. This is independent of created_by provenance." }, "external_ref": { "type": "object", "description": "Permanent, case-sensitive source identity within this workspace, resource type and private/workspace scope. It is independent of API key rotation and retry receipt expiry.", "properties": { "namespace": { "type": "string", "minLength": 1, "description": "A stable name for the source system, such as crm-production." }, "id": { "type": "string", "minLength": 1, "description": "The record ID in that source system." } }, "required": [ "namespace", "id" ], "additionalProperties": false } }, "required": [ "external_ref", "data" ], "additionalProperties": false, "examples": [ { "external_ref": { "namespace": "crm-production", "id": "customer-1042" }, "data": { "title": "Send project proposal", "status": "open", "due_date": "2026-11-13", "company_ref": "e_company_example", "description": "Prepare a proposal for the onboarding project." } } ] } ``` ```json-schema-response { "type": "object", "properties": { "item": { "type": "object", "properties": { "id": { "type": "string", "description": "Stable core:Task record ID. Keep this top-level value when reading or referring to this record. Available actions are linked under Next steps; an ID does not imply the resource can be edited." }, "created_at": { "type": "number", "description": "Time the record was created, in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Time the record most recently changed, in Unix milliseconds. Use with overlapping windows for incremental reads." }, "created_by": { "type": [ "string", "null" ], "description": "Account that originally created the record, or null for a workspace/system-originated record. This is provenance, not its current owner or a Person record ID." }, "private": { "type": "boolean", "description": "True for a member-owned private record. An API key needs approved delegation to that owner; false alone does not bypass resource grants or other access rules." }, "data": { "type": "object", "properties": { "title": { "type": "string", "description": "Short description of the work to complete." }, "status": { "type": "string", "enum": [ "open", "in_progress", "done" ], "description": "Work status: open, in_progress or done. A due date does not automatically change the status." }, "due_date": { "type": "string", "description": "Due date as YYYY-MM-DD, without a time zone or time of day." }, "assignee_ref": { "type": "string", "description": "ID of a `core:Person` record. Find it with [customers.ListPeople](/developers/reference/customers/ListPeople) and use the top-level `id`. This is not an account ID or a display name." }, "description": { "type": "string", "description": "Details of the work to complete." }, "parent_type": { "type": "string", "description": "Record type this task belongs to, such as core:Company." }, "parent_id": { "type": "string", "description": "ID of the record identified by parent_type." }, "company_ref": { "type": "string", "description": "ID of a `core:Company` record. Find it with [customers.ListCompanies](/developers/reference/customers/ListCompanies) and use the top-level `id`. This is not an account ID or a display name." } }, "required": [ "title" ], "additionalProperties": false, "description": "The record's fields.", "title": "Task" } }, "required": [ "id", "created_at", "updated_at", "created_by", "private", "data" ], "additionalProperties": false, "description": "The requested record, including its metadata and data fields.", "title": "TaskRecord" }, "created": { "type": "boolean", "description": "True when this external reference created a record; false when it matched an existing record." } }, "required": [ "item", "created" ], "additionalProperties": false, "examples": [ { "item": { "id": "e_task_example", "created_at": 1794301200000, "updated_at": 1794301200000, "created_by": "a_example", "private": false, "data": { "title": "Send project proposal", "status": "open", "due_date": "2026-11-13", "company_ref": "e_company_example", "description": "Prepare a proposal for the onboarding project." } }, "created": true } ] } ``` --- # Add voice binding Enable a voice capability for a team inbox. The supplied revision identifies the capability configuration reviewed by the caller. POST https://api.brigg.app/v1/operations/voice.AddVoiceBinding ## Access & visibility Allow `voice.AddVoiceBinding` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `inbox_id` | string | Yes | Inbox ID from ListInboxes, or the original inbox_id of an existing binding. Updating cannot move a binding to another inbox. At least 1 character. | | `offering_key` | string | Yes | Exact key from GetVoiceCatalog.offerings. Treat it as an opaque string; do not build it from a capability label. At least 1 character. | | `revision` | string | Yes | Revision from the selected offering, reviewed before enabling it. A changed revision is refused with HTTP 409; re-read the catalogue and review the change. At least 1 character. | | `settings` | [object](#request-settings) | Yes | Complete settings for this offering. For meeting booking, supply booking_link_id from the catalogue's meetings. Updating replaces settings rather than merging individual keys. | | `enabled` | boolean | Yes | Whether this feature is enabled. | ### request.settings | Field | Type | Required | Description | | --- | --- | --- | --- | | `booking_link_id` | string | No | Active booking link ID from GetVoiceCatalog.meetings. Required by the built-in meeting-booking offering; links requiring unsupported extra questions cannot be used for phone booking. | ## Bind a capability to an inbox [Get voice catalogue](/developers/reference/voice/GetVoiceCatalog) returns team/inbox `offerings` and existing `bindings`. An offering supplies a capability such as booking; it is not a speech voice. Copy its `key` to the request's `offering_key`, and copy `revision` exactly. Only enable an available offering. For built-in meeting booking, supply `settings.booking_link_id` from the catalogue's `meetings`: the link must be active and must not require extra questions unsupported by phone booking. Select the request's `inbox_id` from [List inboxes](/developers/reference/support/ListInboxes). The inbox must have an assigned agent and the acting member must have inbox-management authority. A personal assistant instead requires its owner's identity; workspace delegation does not bypass that ownership check. The public catalogue describes the team/inbox workflow. Add creates a binding. Update requires the binding's existing `id` and its original inbox; it cannot move a binding between inboxes. Binding responses call these fields `inbox_id` and `offering_key`; requests use `inbox_id` and `offering_key`. Submit the complete desired `offering_key`, `revision`, `enabled` and `settings`: update is not a partial settings patch. Read the catalogue first to preserve settings you want to retain. A 409 means an offering is no longer available or its revision changed. Re-read the catalogue, review the new capability and submit a new logical request with the reviewed revision. A 400 can mean invalid booking settings; 403 means the acting member cannot manage the target. Inspect the error message for the cause. Test the inbox with [Start voice test](/developers/reference/voice/StartVoiceTest) after changing its capabilities. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Binding ID to retain for updates and removal. | | `inbox_id` | string | Yes | Inbox to which this binding belongs. It is the request's inbox_id. | | `offering_key` | string | Yes | Stable key identifying a published voice capability. | | `revision` | string | Yes | Revision identifying the version of this capability or configuration. | | `enabled` | boolean | Yes | Whether this binding is enabled. The offering's availability and revision are checked when enabling it. | | `settings` | [VoiceBindingSettings](#voicebindingsettings-response-settings) | No | Configuration fields defined by this voice capability. | ### VoiceBindingSettings · response.settings | Field | Type | Required | Description | | --- | --- | --- | --- | | `booking_link_id` | string | No | Active booking link selected for this inbox's meeting-booking capability. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | ## Next steps - [Get voice catalog](/developers/reference/voice/GetVoiceCatalog) - [Start voice test](/developers/reference/voice/StartVoiceTest) - [Update voice binding](/developers/reference/voice/UpdateVoiceBinding) - [List inboxes](/developers/reference/support/ListInboxes) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Enable meeting booking Read the current catalogue and substitute its exact offering key, revision, meeting link and inbox IDs. These example identifiers are fictional. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/voice.AddVoiceBinding' \ -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 '{ "inbox_id": "e_inbox_support", "offering_key": "[\"builtin\",\"brigg\",\"book_meeting\"]", "revision": "revision_booking_1", "enabled": true, "settings": { "booking_link_id": "booking_support" } }' ``` #### 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/voice.AddVoiceBinding", { 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({ "inbox_id": "e_inbox_support", "offering_key": "[\"builtin\",\"brigg\",\"book_meeting\"]", "revision": "revision_booking_1", "enabled": true, "settings": { "booking_link_id": "booking_support" } }), }); 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 = { "inbox_id": "e_inbox_support", "offering_key": "[\"builtin\",\"brigg\",\"book_meeting\"]", "revision": "revision_booking_1", "enabled": True, "settings": { "booking_link_id": "booking_support" } } request = Request( "https://api.brigg.app/v1/operations/voice.AddVoiceBinding", 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 { "id": "voice_binding_booking", "inbox_id": "e_inbox_support", "offering_key": "[\"builtin\",\"brigg\",\"book_meeting\"]", "revision": "revision_booking_1", "enabled": true, "settings": { "booking_link_id": "booking_support" } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "inbox_id": { "type": "string", "minLength": 1, "description": "Inbox ID from ListInboxes, or the original inbox_id of an existing binding. Updating cannot move a binding to another inbox." }, "offering_key": { "type": "string", "minLength": 1, "description": "Exact key from GetVoiceCatalog.offerings. Treat it as an opaque string; do not build it from a capability label." }, "revision": { "type": "string", "minLength": 1, "description": "Revision from the selected offering, reviewed before enabling it. A changed revision is refused with HTTP 409; re-read the catalogue and review the change." }, "settings": { "type": "object", "properties": { "booking_link_id": { "type": "string", "description": "Active booking link ID from GetVoiceCatalog.meetings. Required by the built-in meeting-booking offering; links requiring unsupported extra questions cannot be used for phone booking." } }, "additionalProperties": false, "description": "Complete settings for this offering. For meeting booking, supply booking_link_id from the catalogue's meetings. Updating replaces settings rather than merging individual keys." }, "enabled": { "type": "boolean", "description": "Whether this feature is enabled." } }, "required": [ "inbox_id", "offering_key", "revision", "settings", "enabled" ], "additionalProperties": false, "examples": [ { "inbox_id": "e_inbox_support", "offering_key": "[\"builtin\",\"brigg\",\"book_meeting\"]", "revision": "revision_booking_1", "enabled": true, "settings": { "booking_link_id": "booking_support" } } ] } ``` ```json-schema-response { "type": "object", "properties": { "id": { "type": "string", "description": "Binding ID to retain for updates and removal." }, "inbox_id": { "type": "string", "description": "Inbox to which this binding belongs. It is the request's inbox_id." }, "offering_key": { "type": "string", "description": "Stable key identifying a published voice capability." }, "revision": { "type": "string", "description": "Revision identifying the version of this capability or configuration." }, "enabled": { "type": "boolean", "description": "Whether this binding is enabled. The offering's availability and revision are checked when enabling it." }, "settings": { "description": "Configuration fields defined by this voice capability.", "title": "VoiceBindingSettings", "type": "object", "properties": { "booking_link_id": { "type": "string", "description": "Active booking link selected for this inbox's meeting-booking capability." } }, "required": [], "additionalProperties": false } }, "required": [ "id", "inbox_id", "offering_key", "revision", "enabled" ], "additionalProperties": false, "examples": [ { "id": "voice_binding_booking", "inbox_id": "e_inbox_support", "offering_key": "[\"builtin\",\"brigg\",\"book_meeting\"]", "revision": "revision_booking_1", "enabled": true, "settings": { "booking_link_id": "booking_support" } } ] } ``` --- # Remove voice binding Remove a capability from a phone assistant. The caller must have management permission for that assistant. POST https://api.brigg.app/v1/operations/voice.RemoveVoiceBinding ## Access & visibility Allow `voice.RemoveVoiceBinding` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | Use id from bindings. Removing a binding does not delete the source capability. [voice.GetVoiceCatalog](/developers/reference/voice/GetVoiceCatalog). At least 1 character. | ## Disconnect a capability Find the binding in [Get voice catalogue](/developers/reference/voice/GetVoiceCatalog) and pass its `id`. Removal disconnects that capability from the assistant; it does not delete the source app, meeting booking link or inbox. There is no offering revision or settings body to send. The acting member needs management authority over the target inbox. For a personal assistant, only its owner can manage the binding. If the inbox has been deleted or its agent unassigned, a workspace manager can remove the orphaned binding. A binding already absent returns `ok: true`. Retry the original action with its original idempotency key. Re-read the catalogue to confirm the remaining capabilities. [Start voice test](/developers/reference/voice/StartVoiceTest) can check the assistant after the change. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | ## Next steps - [Get voice catalog](/developers/reference/voice/GetVoiceCatalog) - [Start voice test](/developers/reference/voice/StartVoiceTest) - [Add voice binding](/developers/reference/voice/AddVoiceBinding) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Remove a booking capability Use the binding's id from GetVoiceCatalog. The booking link itself remains available. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/voice.RemoveVoiceBinding' \ -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": "vb_booking_support" }' ``` #### 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/voice.RemoveVoiceBinding", { 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": "vb_booking_support" }), }); 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": "vb_booking_support" } request = Request( "https://api.brigg.app/v1/operations/voice.RemoveVoiceBinding", 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 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Use id from bindings. Removing a binding does not delete the source capability. [voice.GetVoiceCatalog](/developers/reference/voice/GetVoiceCatalog)." } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "vb_booking_support" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." } }, "required": [ "ok" ], "additionalProperties": false, "examples": [ { "ok": true } ] } ``` --- # Update voice binding Change a phone assistant capability's settings or enable or disable it. POST https://api.brigg.app/v1/operations/voice.UpdateVoiceBinding ## Access & visibility Allow `voice.UpdateVoiceBinding` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | Use id from bindings, not key from offerings. [voice.GetVoiceCatalog](/developers/reference/voice/GetVoiceCatalog). At least 1 character. | | `inbox_id` | string | Yes | Inbox ID from ListInboxes, or the original inbox_id of an existing binding. Updating cannot move a binding to another inbox. At least 1 character. | | `offering_key` | string | Yes | Exact key from GetVoiceCatalog.offerings. Treat it as an opaque string; do not build it from a capability label. At least 1 character. | | `revision` | string | Yes | Revision from the selected offering, reviewed before enabling it. A changed revision is refused with HTTP 409; re-read the catalogue and review the change. At least 1 character. | | `settings` | [object](#request-settings) | Yes | Complete settings for this offering. For meeting booking, supply booking_link_id from the catalogue's meetings. Updating replaces settings rather than merging individual keys. | | `enabled` | boolean | Yes | Whether this feature is enabled. | ### request.settings | Field | Type | Required | Description | | --- | --- | --- | --- | | `booking_link_id` | string | No | Active booking link ID from GetVoiceCatalog.meetings. Required by the built-in meeting-booking offering; links requiring unsupported extra questions cannot be used for phone booking. | ## Bind a capability to an inbox [Get voice catalogue](/developers/reference/voice/GetVoiceCatalog) returns team/inbox `offerings` and existing `bindings`. An offering supplies a capability such as booking; it is not a speech voice. Copy its `key` to the request's `offering_key`, and copy `revision` exactly. Only enable an available offering. For built-in meeting booking, supply `settings.booking_link_id` from the catalogue's `meetings`: the link must be active and must not require extra questions unsupported by phone booking. Select the request's `inbox_id` from [List inboxes](/developers/reference/support/ListInboxes). The inbox must have an assigned agent and the acting member must have inbox-management authority. A personal assistant instead requires its owner's identity; workspace delegation does not bypass that ownership check. The public catalogue describes the team/inbox workflow. Add creates a binding. Update requires the binding's existing `id` and its original inbox; it cannot move a binding between inboxes. Binding responses call these fields `inbox_id` and `offering_key`; requests use `inbox_id` and `offering_key`. Submit the complete desired `offering_key`, `revision`, `enabled` and `settings`: update is not a partial settings patch. Read the catalogue first to preserve settings you want to retain. A 409 means an offering is no longer available or its revision changed. Re-read the catalogue, review the new capability and submit a new logical request with the reviewed revision. A 400 can mean invalid booking settings; 403 means the acting member cannot manage the target. Inspect the error message for the cause. Test the inbox with [Start voice test](/developers/reference/voice/StartVoiceTest) after changing its capabilities. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Binding ID to retain for updates and removal. | | `inbox_id` | string | Yes | Inbox to which this binding belongs. It is the request's inbox_id. | | `offering_key` | string | Yes | Stable key identifying a published voice capability. | | `revision` | string | Yes | Revision identifying the version of this capability or configuration. | | `enabled` | boolean | Yes | Whether this binding is enabled. The offering's availability and revision are checked when enabling it. | | `settings` | [VoiceBindingSettings](#voicebindingsettings-response-settings) | No | Configuration fields defined by this voice capability. | ### VoiceBindingSettings · response.settings | Field | Type | Required | Description | | --- | --- | --- | --- | | `booking_link_id` | string | No | Active booking link selected for this inbox's meeting-booking capability. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | ## Next steps - [Get voice catalog](/developers/reference/voice/GetVoiceCatalog) - [Start voice test](/developers/reference/voice/StartVoiceTest) - [List inboxes](/developers/reference/support/ListInboxes) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Enable meeting booking Read the current catalogue and substitute its exact offering key, revision, meeting link and inbox IDs. These example identifiers are fictional. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/voice.UpdateVoiceBinding' \ -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": "voice_binding_booking", "inbox_id": "e_inbox_support", "offering_key": "[\"builtin\",\"brigg\",\"book_meeting\"]", "revision": "revision_booking_1", "enabled": true, "settings": { "booking_link_id": "booking_support" } }' ``` #### 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/voice.UpdateVoiceBinding", { 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": "voice_binding_booking", "inbox_id": "e_inbox_support", "offering_key": "[\"builtin\",\"brigg\",\"book_meeting\"]", "revision": "revision_booking_1", "enabled": true, "settings": { "booking_link_id": "booking_support" } }), }); 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": "voice_binding_booking", "inbox_id": "e_inbox_support", "offering_key": "[\"builtin\",\"brigg\",\"book_meeting\"]", "revision": "revision_booking_1", "enabled": True, "settings": { "booking_link_id": "booking_support" } } request = Request( "https://api.brigg.app/v1/operations/voice.UpdateVoiceBinding", 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 { "id": "voice_binding_booking", "inbox_id": "e_inbox_support", "offering_key": "[\"builtin\",\"brigg\",\"book_meeting\"]", "revision": "revision_booking_1", "enabled": true, "settings": { "booking_link_id": "booking_support" } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Use id from bindings, not key from offerings. [voice.GetVoiceCatalog](/developers/reference/voice/GetVoiceCatalog)." }, "inbox_id": { "type": "string", "minLength": 1, "description": "Inbox ID from ListInboxes, or the original inbox_id of an existing binding. Updating cannot move a binding to another inbox." }, "offering_key": { "type": "string", "minLength": 1, "description": "Exact key from GetVoiceCatalog.offerings. Treat it as an opaque string; do not build it from a capability label." }, "revision": { "type": "string", "minLength": 1, "description": "Revision from the selected offering, reviewed before enabling it. A changed revision is refused with HTTP 409; re-read the catalogue and review the change." }, "settings": { "type": "object", "properties": { "booking_link_id": { "type": "string", "description": "Active booking link ID from GetVoiceCatalog.meetings. Required by the built-in meeting-booking offering; links requiring unsupported extra questions cannot be used for phone booking." } }, "additionalProperties": false, "description": "Complete settings for this offering. For meeting booking, supply booking_link_id from the catalogue's meetings. Updating replaces settings rather than merging individual keys." }, "enabled": { "type": "boolean", "description": "Whether this feature is enabled." } }, "required": [ "id", "inbox_id", "offering_key", "revision", "settings", "enabled" ], "additionalProperties": false, "examples": [ { "id": "voice_binding_booking", "inbox_id": "e_inbox_support", "offering_key": "[\"builtin\",\"brigg\",\"book_meeting\"]", "revision": "revision_booking_1", "enabled": true, "settings": { "booking_link_id": "booking_support" } } ] } ``` ```json-schema-response { "type": "object", "properties": { "id": { "type": "string", "description": "Binding ID to retain for updates and removal." }, "inbox_id": { "type": "string", "description": "Inbox to which this binding belongs. It is the request's inbox_id." }, "offering_key": { "type": "string", "description": "Stable key identifying a published voice capability." }, "revision": { "type": "string", "description": "Revision identifying the version of this capability or configuration." }, "enabled": { "type": "boolean", "description": "Whether this binding is enabled. The offering's availability and revision are checked when enabling it." }, "settings": { "description": "Configuration fields defined by this voice capability.", "title": "VoiceBindingSettings", "type": "object", "properties": { "booking_link_id": { "type": "string", "description": "Active booking link selected for this inbox's meeting-booking capability." } }, "required": [], "additionalProperties": false } }, "required": [ "id", "inbox_id", "offering_key", "revision", "enabled" ], "additionalProperties": false, "examples": [ { "id": "voice_binding_booking", "inbox_id": "e_inbox_support", "offering_key": "[\"builtin\",\"brigg\",\"book_meeting\"]", "revision": "revision_booking_1", "enabled": true, "settings": { "booking_link_id": "booking_support" } } ] } ``` --- # Get voice catalog List available team-inbox voice capabilities, their revisions, configured bindings and eligible booking links. POST https://api.brigg.app/v1/operations/voice.GetVoiceCatalog ## Access & visibility Allow `voice.GetVoiceCatalog` on your API key. Resource read permissions: `core:Inbox`. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/permissions) ## Request No parameters. Send an empty JSON object (`{}`). ## Bind a capability to an inbox [Get voice catalogue](/developers/reference/voice/GetVoiceCatalog) returns team/inbox `offerings` and existing `bindings`. An offering supplies a capability such as booking; it is not a speech voice. Copy its `key` to the request's `offering_key`, and copy `revision` exactly. Only enable an available offering. For built-in meeting booking, supply `settings.booking_link_id` from the catalogue's `meetings`: the link must be active and must not require extra questions unsupported by phone booking. Select the request's `inbox_id` from [List inboxes](/developers/reference/support/ListInboxes). The inbox must have an assigned agent and the acting member must have inbox-management authority. A personal assistant instead requires its owner's identity; workspace delegation does not bypass that ownership check. The public catalogue describes the team/inbox workflow. Add creates a binding. Update requires the binding's existing `id` and its original inbox; it cannot move a binding between inboxes. Binding responses call these fields `inbox_id` and `offering_key`; requests use `inbox_id` and `offering_key`. Submit the complete desired `offering_key`, `revision`, `enabled` and `settings`: update is not a partial settings patch. Read the catalogue first to preserve settings you want to retain. A 409 means an offering is no longer available or its revision changed. Re-read the catalogue, review the new capability and submit a new logical request with the reviewed revision. A 400 can mean invalid booking settings; 403 means the acting member cannot manage the target. Inspect the error message for the cause. Test the inbox with [Start voice test](/developers/reference/voice/StartVoiceTest) after changing its capabilities. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `offerings` | array of [VoiceOffering](#voiceoffering-response-offerings) | Yes | Available voice capabilities that can be bound to an inbox assistant. | | `bindings` | array of [object](#response-bindings) | Yes | Configured connections between an inbox assistant and voice capabilities. | | `meetings` | array of [object](#response-meetings) | Yes | Booking links available to the voice assistant. | ### VoiceOffering · response.offerings[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `key` | string | Yes | Stable key identifying this option within its collection; distinct from its display label. | | `source` | [object](#response-offerings-source) | Yes | App or integration supplying the voice capability. | | `revision` | string | Yes | Revision identifying the version of this capability or configuration. | | `source_version` | string | Yes | Published source version used by this capability. | | `capability` | [object](#response-offerings-capability) | Yes | Voice capability exposed by an app or integration. | | `available` | boolean | Yes | Whether this voice capability is available for the selected inbox. Allowed: `false`, `true`. | | `reason` | string | No | Explanation of why this outcome occurred. | | `follows_deploy` | boolean | No | Whether this binding follows new deployments of its source capability. Allowed: `true`. | ### response.offerings[].source | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Category identifying which variant of this model applies. Allowed: `"app"`, `"builtin"`, `"integration"`. | | `id` | string | Yes | Unique identifier. Use the value returned by a create or list operation. | | `label` | string | Yes | Human-readable label shown for this item; use its ID or key in API calls. | ### response.offerings[].capability | Field | Type | Required | Description | | --- | --- | --- | --- | | `kind` | string | Yes | Category identifying which variant of this model applies. Allowed: `"read"`, `"write"`. | | `label` | string | Yes | Human-readable label shown for this item; use its ID or key in API calls. | | `description` | string | Yes | Descriptive text. | | `id` | string | Yes | Unique identifier. Use the value returned by a create or list operation. | | `changes` | map of [object (3 variants)](#response-offerings-capability-changes) | Yes | Setting changes to apply to the existing binding. | | `input` | map of JSON values | No | A JSON Schema document describing the accepted value. See https://json-schema.org/understanding-json-schema/. | | `source` | string | No | App or integration supplying the voice capability. | | `settings` | [object](#response-offerings-capability-settings) | No | Configuration fields defined by this voice capability. | | `target` | [object](#response-offerings-capability-target) | No | Record or operation targeted by this capability. | | `builtin` | string | No | Whether the capability is supplied by Brigg. Allowed: `"take_message"`, `"book_meeting"`, `"manage_calendar"`, `"search_knowledge"`, `"transfer_call"`, `"end_call"`. | ### response.offerings[].capability.changes.* #### Variant 1 | Field | Type | Required | Description | | --- | --- | --- | --- | | `value` | null or string or number or boolean | Yes | Literal value to write when this capability applies the change. | #### Variant 2 | Field | Type | Required | Description | | --- | --- | --- | --- | | `fromField` | string | Yes | Read the change value from this field on the selected record. | #### Variant 3 | Field | Type | Required | Description | | --- | --- | --- | --- | | `fromInput` | string | Yes | Read the change value from this named capability input. | ### response.offerings[].capability.settings | Field | Type | Required | Description | | --- | --- | --- | --- | | `booking_link_id` | string | No | Booking link identifier. | ### response.offerings[].capability.target | Field | Type | Required | Description | | --- | --- | --- | --- | | `where` | map of null or string or number or boolean or [object](#response-offerings-capability-target-where) | Yes | Record-selection conditions used by the capability. | | `type` | string | Yes | Type identifying which variant of this model applies. | | `fields` | array of string | Yes | Named fields applicable to this item. | | `bundle_id` | string | Yes | Bundle identifier. | | `owner_field` | string | Yes | Field identifying the capability's owning record. | | `owner_type` | string | Yes | Resource type of the capability's owning record. Allowed: `"company"`, `"person"`. | ### response.offerings[].capability.target.where.* | Field | Type | Required | Description | | --- | --- | --- | --- | | `fromInput` | string | Yes | Read the change value from this named capability input. | ### response.bindings[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Unique identifier. Use the value returned by a create or list operation. | | `inbox_id` | string | Yes | Inbox identifier. | | `offering_key` | string | Yes | Stable key identifying a published voice capability. | | `revision` | string | Yes | Revision identifying the version of this capability or configuration. | | `enabled` | boolean | Yes | Whether this feature is enabled. | | `settings` | [VoiceBindingSettings](#voicebindingsettings-response-bindings-settings) | No | Configuration fields defined by this voice capability. | ### VoiceBindingSettings · response.bindings[].settings | Field | Type | Required | Description | | --- | --- | --- | --- | | `booking_link_id` | string | No | Booking link identifier. | ### response.meetings[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Unique identifier. Use the value returned by a create or list operation. | | `label` | string | Yes | Human-readable label shown for this item; use its ID or key in API calls. | | `owner` | string | Yes | Record to which the voice capability belongs. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [Start voice test](/developers/reference/voice/StartVoiceTest) - [Update voice binding](/developers/reference/voice/UpdateVoiceBinding) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Available booking capability Use the offering key and revision with a valid meeting link. Existing bindings identify what the inbox currently has enabled. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/voice.GetVoiceCatalog' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{}' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/voice.GetVoiceCatalog", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/voice.GetVoiceCatalog", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "offerings": [ { "key": "[\"builtin\",\"brigg\",\"book_meeting\"]", "source": { "kind": "builtin", "id": "brigg", "label": "Brigg" }, "revision": "revision_booking_1", "source_version": "1", "capability": { "kind": "write", "label": "Book a meeting", "description": "Book a time using an active meeting link.", "id": "book_meeting", "changes": {}, "builtin": "book_meeting" }, "available": true } ], "bindings": [ { "id": "voice_binding_booking", "inbox_id": "e_inbox_support", "offering_key": "[\"builtin\",\"brigg\",\"book_meeting\"]", "revision": "revision_booking_1", "enabled": true, "settings": { "booking_link_id": "booking_support" } } ], "meetings": [ { "id": "booking_support", "label": "Support consultation", "owner": "Alex Morgan" } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": {}, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "offerings": { "type": "array", "items": { "title": "VoiceOffering", "type": "object", "properties": { "key": { "type": "string", "description": "Stable key identifying this option within its collection; distinct from its display label." }, "source": { "type": "object", "properties": { "kind": { "type": "string", "enum": [ "app", "builtin", "integration" ], "description": "Category identifying which variant of this model applies." }, "id": { "type": "string", "description": "Unique identifier. Use the value returned by a create or list operation." }, "label": { "type": "string", "description": "Human-readable label shown for this item; use its ID or key in API calls." } }, "required": [ "kind", "id", "label" ], "additionalProperties": false, "description": "App or integration supplying the voice capability." }, "revision": { "type": "string", "description": "Revision identifying the version of this capability or configuration." }, "source_version": { "type": "string", "description": "Published source version used by this capability." }, "capability": { "type": "object", "properties": { "kind": { "type": "string", "enum": [ "read", "write" ], "description": "Category identifying which variant of this model applies." }, "label": { "type": "string", "description": "Human-readable label shown for this item; use its ID or key in API calls." }, "description": { "type": "string", "description": "Descriptive text." }, "id": { "type": "string", "description": "Unique identifier. Use the value returned by a create or list operation." }, "changes": { "type": "object", "additionalProperties": { "anyOf": [ { "type": "object", "properties": { "value": { "anyOf": [ { "type": "null" }, { "type": "string" }, { "type": "number" }, { "type": "boolean", "const": false }, { "type": "boolean", "const": true } ], "description": "Literal value to write when this capability applies the change." } }, "required": [ "value" ], "additionalProperties": false }, { "type": "object", "properties": { "fromField": { "type": "string", "description": "Read the change value from this field on the selected record." } }, "required": [ "fromField" ], "additionalProperties": false }, { "type": "object", "properties": { "fromInput": { "type": "string", "description": "Read the change value from this named capability input." } }, "required": [ "fromInput" ], "additionalProperties": false } ] }, "description": "Setting changes to apply to the existing binding." }, "input": { "type": "object", "additionalProperties": true, "description": "A JSON Schema document describing the accepted value. See https://json-schema.org/understanding-json-schema/." }, "source": { "type": "string", "description": "App or integration supplying the voice capability." }, "settings": { "type": "object", "properties": { "booking_link_id": { "type": "string", "description": "Booking link identifier." } }, "required": [], "additionalProperties": false, "description": "Configuration fields defined by this voice capability." }, "target": { "type": "object", "properties": { "where": { "type": "object", "additionalProperties": { "anyOf": [ { "type": "null" }, { "type": "string" }, { "type": "number" }, { "type": "boolean", "const": false }, { "type": "boolean", "const": true }, { "type": "object", "properties": { "fromInput": { "type": "string", "description": "Read the change value from this named capability input." } }, "required": [ "fromInput" ], "additionalProperties": false } ] }, "description": "Record-selection conditions used by the capability." }, "type": { "type": "string", "description": "Type identifying which variant of this model applies." }, "fields": { "type": "array", "items": { "type": "string" }, "description": "Named fields applicable to this item." }, "bundle_id": { "type": "string", "description": "Bundle identifier." }, "owner_field": { "type": "string", "description": "Field identifying the capability's owning record." }, "owner_type": { "type": "string", "enum": [ "company", "person" ], "description": "Resource type of the capability's owning record." } }, "required": [ "where", "type", "fields", "bundle_id", "owner_field", "owner_type" ], "additionalProperties": false, "description": "Record or operation targeted by this capability." }, "builtin": { "type": "string", "enum": [ "take_message", "book_meeting", "manage_calendar", "search_knowledge", "transfer_call", "end_call" ], "description": "Whether the capability is supplied by Brigg." } }, "required": [ "kind", "label", "description", "id", "changes" ], "additionalProperties": false, "description": "Voice capability exposed by an app or integration." }, "available": { "type": "boolean", "enum": [ false, true ], "description": "Whether this voice capability is available for the selected inbox." }, "reason": { "type": "string", "description": "Explanation of why this outcome occurred." }, "follows_deploy": { "type": "boolean", "enum": [ true ], "description": "Whether this binding follows new deployments of its source capability." } }, "required": [ "key", "source", "revision", "source_version", "capability", "available" ], "additionalProperties": false }, "description": "Available voice capabilities that can be bound to an inbox assistant." }, "bindings": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier. Use the value returned by a create or list operation." }, "inbox_id": { "type": "string", "description": "Inbox identifier." }, "offering_key": { "type": "string", "description": "Stable key identifying a published voice capability." }, "revision": { "type": "string", "description": "Revision identifying the version of this capability or configuration." }, "enabled": { "type": "boolean", "description": "Whether this feature is enabled." }, "settings": { "description": "Configuration fields defined by this voice capability.", "title": "VoiceBindingSettings", "type": "object", "properties": { "booking_link_id": { "type": "string", "description": "Booking link identifier." } }, "required": [], "additionalProperties": false } }, "required": [ "id", "inbox_id", "offering_key", "revision", "enabled" ], "additionalProperties": false }, "description": "Configured connections between an inbox assistant and voice capabilities." }, "meetings": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier. Use the value returned by a create or list operation." }, "label": { "type": "string", "description": "Human-readable label shown for this item; use its ID or key in API calls." }, "owner": { "type": "string", "description": "Record to which the voice capability belongs." } }, "required": [ "id", "label", "owner" ], "additionalProperties": false }, "description": "Booking links available to the voice assistant." } }, "required": [ "offerings", "bindings", "meetings" ], "additionalProperties": false, "examples": [ { "offerings": [ { "key": "[\"builtin\",\"brigg\",\"book_meeting\"]", "source": { "kind": "builtin", "id": "brigg", "label": "Brigg" }, "revision": "revision_booking_1", "source_version": "1", "capability": { "kind": "write", "label": "Book a meeting", "description": "Book a time using an active meeting link.", "id": "book_meeting", "changes": {}, "builtin": "book_meeting" }, "available": true } ], "bindings": [ { "id": "voice_binding_booking", "inbox_id": "e_inbox_support", "offering_key": "[\"builtin\",\"brigg\",\"book_meeting\"]", "revision": "revision_booking_1", "enabled": true, "settings": { "booking_link_id": "booking_support" } } ], "meetings": [ { "id": "booking_support", "label": "Support consultation", "owner": "Alex Morgan" } ] } ] } ``` --- # End voice test End a voice test session. Further turns cannot be added after the session ends. POST https://api.brigg.app/v1/operations/voice.EndVoiceTest ## Access & visibility Allow `voice.EndVoiceTest` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `test_id` | string | Yes | Keep the returned test_id for this temporary session. Expired sessions require a new test. [voice.StartVoiceTest](/developers/reference/voice/StartVoiceTest). At least 1 character. | ## Run a conversation test Start a test for the intended inbox and retain its `test_id`. Text clients can use [Run voice test turn](/developers/reference/voice/RunVoiceTestTurn); an audio connection URL is only needed for an audio client. Keep temporary connection URLs secret. Pass the simulated caller's utterance and previous conversation history in order. Keep a stable `turn_id` for a retried turn. Review the returned reply and capability trace; a simulated response is not evidence that a real customer call succeeded. [Review voice test](/developers/reference/voice/ReviewVoiceTest) accepts the conversation transcript for feedback. End the session when finished; an expired session needs a new start. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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 | `voice_test_expired` | The test expired, is unknown, or belongs to another member. Start a new test under the intended approved member. | ## Next steps - [Start voice test](/developers/reference/voice/StartVoiceTest) - [Run voice test turn](/developers/reference/voice/RunVoiceTestTurn) - [Review voice test](/developers/reference/voice/ReviewVoiceTest) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/voice.EndVoiceTest' \ -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 '{ "test_id": "voice_test_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/voice.EndVoiceTest", { 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({ "test_id": "voice_test_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 = { "test_id": "voice_test_kickoff" } request = Request( "https://api.brigg.app/v1/operations/voice.EndVoiceTest", 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 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "test_id": { "type": "string", "minLength": 1, "description": "Keep the returned test_id for this temporary session. Expired sessions require a new test. [voice.StartVoiceTest](/developers/reference/voice/StartVoiceTest)." } }, "required": [ "test_id" ], "additionalProperties": false, "examples": [ { "test_id": "voice_test_kickoff" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." } }, "required": [ "ok" ], "additionalProperties": false, "examples": [ { "ok": true } ] } ``` --- # Review voice test Review a test-call transcript against the voice agent's instructions. Returns handled requests, gaps and suggested instruction changes. POST https://api.brigg.app/v1/operations/voice.ReviewVoiceTest ## Access & visibility Allow `voice.ReviewVoiceTest` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `test_id` | string | Yes | Keep the returned test_id for this temporary session. Expired sessions require a new test. [voice.StartVoiceTest](/developers/reference/voice/StartVoiceTest). At least 1 character. | | `transcript` | array of [object](#request-transcript) | Yes | Complete caller/agent conversation to review in order. Brigg does not reconstruct it from previous RunVoiceTestTurn calls. At most 200 items. | ### request.transcript[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `role` | string | Yes | Conversation speaker: caller is the simulated customer; agent is the assistant. This is not a workspace permission or member role. Allowed: `"caller"`, `"agent"`. | | `text` | string | Yes | The words spoken by this participant, in conversation order. At most 4000 characters. | ## Run a conversation test Start a test for the intended inbox and retain its `test_id`. Text clients can use [Run voice test turn](/developers/reference/voice/RunVoiceTestTurn); an audio connection URL is only needed for an audio client. Keep temporary connection URLs secret. Pass the simulated caller's utterance and previous conversation history in order. Keep a stable `turn_id` for a retried turn. Review the returned reply and capability trace; a simulated response is not evidence that a real customer call succeeded. [Review voice test](/developers/reference/voice/ReviewVoiceTest) accepts the conversation transcript for feedback. End the session when finished; an expired session needs a new start. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `rows` | array of [ReviewVoiceTestRows](#reviewvoicetestrows-response-rows) | Yes | Generated feedback on the submitted transcript. Empty means no feedback was returned, including when generation could not produce a review; it is not a pass/fail certification. | ### ReviewVoiceTestRows · response.rows[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `status` | string | Yes | ok describes a handled instruction; gap identifies missing guidance. These are review findings, not the status of the voice test session. Allowed: `"ok"`, `"gap"`. | | `text` | string | Yes | Text content. | | `suggestion` | string | No | Suggested change to the assistant's instructions based on the review. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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 | `voice_test_expired` | The test expired, is unknown, or belongs to another member. Start a new test under the intended approved member. | ## Next steps - [Start voice test](/developers/reference/voice/StartVoiceTest) - [Run voice test turn](/developers/reference/voice/RunVoiceTestTurn) - [End voice test](/developers/reference/voice/EndVoiceTest) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/voice.ReviewVoiceTest' \ -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 '{ "test_id": "voice_test_kickoff", "transcript": [ { "role": "caller", "text": "Discuss the pilot timeline and agree on next steps." } ] }' ``` #### 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/voice.ReviewVoiceTest", { 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({ "test_id": "voice_test_kickoff", "transcript": [ { "role": "caller", "text": "Discuss the pilot timeline and agree on next steps." } ] }), }); 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 = { "test_id": "voice_test_kickoff", "transcript": [ { "role": "caller", "text": "Discuss the pilot timeline and agree on next steps." } ] } request = Request( "https://api.brigg.app/v1/operations/voice.ReviewVoiceTest", 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 { "rows": [ { "status": "ok", "text": "Discuss the pilot timeline and agree on next steps." } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "test_id": { "type": "string", "minLength": 1, "description": "Keep the returned test_id for this temporary session. Expired sessions require a new test. [voice.StartVoiceTest](/developers/reference/voice/StartVoiceTest)." }, "transcript": { "type": "array", "items": { "type": "object", "properties": { "role": { "type": "string", "enum": [ "caller", "agent" ], "description": "Conversation speaker: caller is the simulated customer; agent is the assistant. This is not a workspace permission or member role." }, "text": { "type": "string", "maxLength": 4000, "description": "The words spoken by this participant, in conversation order." } }, "required": [ "role", "text" ], "additionalProperties": false }, "maxItems": 200, "description": "Complete caller/agent conversation to review in order. Brigg does not reconstruct it from previous RunVoiceTestTurn calls." } }, "required": [ "test_id", "transcript" ], "additionalProperties": false, "examples": [ { "test_id": "voice_test_kickoff", "transcript": [ { "role": "caller", "text": "Discuss the pilot timeline and agree on next steps." } ] } ] } ``` ```json-schema-response { "type": "object", "properties": { "rows": { "type": "array", "items": { "title": "ReviewVoiceTestRows", "type": "object", "properties": { "status": { "type": "string", "enum": [ "ok", "gap" ], "description": "ok describes a handled instruction; gap identifies missing guidance. These are review findings, not the status of the voice test session." }, "text": { "type": "string", "description": "Text content." }, "suggestion": { "type": "string", "description": "Suggested change to the assistant's instructions based on the review." } }, "required": [ "status", "text" ], "additionalProperties": false }, "description": "Generated feedback on the submitted transcript. Empty means no feedback was returned, including when generation could not produce a review; it is not a pass/fail certification." } }, "required": [ "rows" ], "additionalProperties": false, "examples": [ { "rows": [ { "status": "ok", "text": "Discuss the pilot timeline and agree on next steps." } ] } ] } ``` --- # Run voice test turn Submit a simulated caller's message to a voice test session. Returns the assistant's reply and a trace of the capabilities it would use. POST https://api.brigg.app/v1/operations/voice.RunVoiceTestTurn ## Access & visibility Allow `voice.RunVoiceTestTurn` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `test_id` | string | Yes | Keep the returned test_id for this temporary session. Expired sessions require a new test. [voice.StartVoiceTest](/developers/reference/voice/StartVoiceTest). At least 1 character. | | `utterance` | string | Yes | What the caller says. At least 1 character. | | `history` | array of [object](#request-history) | No | Earlier caller and assistant lines, oldest first. Omit or use [] for the first turn. Send accumulated conversation on later turns; the current utterance belongs only in utterance, not duplicated here. Default: `[]`. | | `turn_id` | string | Yes | Client-chosen identifier unique to one logical turn within this test. Keep it and the HTTP idempotency key unchanged when retrying that same utterance/history; choose new values for the next turn. At least 1 character. | ### request.history[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `role` | string | Yes | Conversation speaker: caller is the simulated customer; agent is the assistant. This is not a workspace permission or member role. Allowed: `"caller"`, `"agent"`. | | `text` | string | Yes | The words spoken by this participant, in conversation order. | ## Inspect a test turn Send each new caller utterance with the prior conversation, and append the returned text as an agent line for the next turn. A typed test does not require the audio socket. Keep the same approved member throughout the session. A trace entry currently includes capabilityId, source, label, kind, result and durationMs. These are optional diagnostics within an open JSON value, not stable fields to build business logic around. The result can report success, refusal, failure or uncertainty; inspect it instead of treating HTTP 200 or plausible reply text as success. Ignore unfamiliar diagnostic properties. The test simulates changes rather than performing the corresponding customer action, but model work can consume workspace credit. Use [Review voice test](/developers/reference/voice/ReviewVoiceTest) with the complete transcript for feedback. Its review can be empty when no feedback was generated; that is not proof of a flawless assistant. End the test when finished. An expired, unknown or differently owned test requires a fresh session. ## Run a conversation test Start a test for the intended inbox and retain its `test_id`. Text clients can use [Run voice test turn](/developers/reference/voice/RunVoiceTestTurn); an audio connection URL is only needed for an audio client. Keep temporary connection URLs secret. Pass the simulated caller's utterance and previous conversation history in order. Keep a stable `turn_id` for a retried turn. Review the returned reply and capability trace; a simulated response is not evidence that a real customer call succeeded. [Review voice test](/developers/reference/voice/ReviewVoiceTest) accepts the conversation transcript for feedback. End the session when finished; an expired session needs a new start. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `text` | string | Yes | Assistant's reply to the current utterance. Display it and append it as an agent line to the next turn's history. Text alone does not prove a capability succeeded. | | `trace` | array of JSON value | No | Ordered capability attempts for this turn, not a history of the whole test. [] means no capability was attempted. Entries are diagnostic JSON; the public contract does not fix their nested shape. See Inspect a test turn for how to read available diagnostics. | | `timings` | [RunVoiceTestTurnTimings](#runvoicetestturntimings-response-timings) | No | Server-side durations in milliseconds for this turn, not audio latency or client network time. These measurements are diagnostic, not a response-time guarantee. | ### RunVoiceTestTurnTimings · response.timings | Field | Type | Required | Description | | --- | --- | --- | --- | | `total_ms` | number | Yes | Elapsed duration of the turn-processing loop. May include overhead beyond the three component measurements. | | `decide_ms` | number | Yes | Time spent on the initial model decision before any capability execution. | | `execute_ms` | number | Yes | Total time spent executing or simulating the requested capabilities. | | `compose_ms` | number | Yes | Time spent on subsequent model calls after the initial decision, including follow-up decisions and composing a reply. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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 | `voice_test_expired` | The test expired, is unknown, or belongs to another member. Start a new test under the intended approved member. | | 409 | `voice_test_ended` | The test was closed. Start a new session instead of retrying this turn. | ## Next steps - [Start voice test](/developers/reference/voice/StartVoiceTest) - [Review voice test](/developers/reference/voice/ReviewVoiceTest) - [End voice test](/developers/reference/voice/EndVoiceTest) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Ask the first question The assistant asks for clarification without invoking a capability, so trace is empty. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/voice.RunVoiceTestTurn' \ -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 '{ "test_id": "test_support_preview", "turn_id": "turn-1", "utterance": "I would like to book a meeting.", "history": [] }' ``` #### 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/voice.RunVoiceTestTurn", { 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({ "test_id": "test_support_preview", "turn_id": "turn-1", "utterance": "I would like to book a meeting.", "history": [] }), }); 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 = { "test_id": "test_support_preview", "turn_id": "turn-1", "utterance": "I would like to book a meeting.", "history": [] } request = Request( "https://api.brigg.app/v1/operations/voice.RunVoiceTestTurn", 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 { "text": "What day and time work best for you?", "trace": [], "timings": { "decide_ms": 430, "execute_ms": 0, "compose_ms": 0, "total_ms": 447 } } ``` ### Continue the conversation Include earlier lines once, then send the new utterance separately. This illustrative turn reports a refused capability; no booking was created. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/voice.RunVoiceTestTurn' \ -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 '{ "test_id": "test_support_preview", "turn_id": "turn-2", "utterance": "Tuesday morning, please.", "history": [ { "role": "caller", "text": "I would like to book a meeting." }, { "role": "agent", "text": "What day and time work best for you?" } ] }' ``` #### 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/voice.RunVoiceTestTurn", { 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({ "test_id": "test_support_preview", "turn_id": "turn-2", "utterance": "Tuesday morning, please.", "history": [ { "role": "caller", "text": "I would like to book a meeting." }, { "role": "agent", "text": "What day and time work best for you?" } ] }), }); 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 = { "test_id": "test_support_preview", "turn_id": "turn-2", "utterance": "Tuesday morning, please.", "history": [ { "role": "caller", "text": "I would like to book a meeting." }, { "role": "agent", "text": "What day and time work best for you?" } ] } request = Request( "https://api.brigg.app/v1/operations/voice.RunVoiceTestTurn", 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 { "text": "Please choose a meeting type before we check times.", "trace": [ { "capabilityId": "booking-preview", "source": "Support", "label": "Book meeting", "kind": "write", "result": { "status": "refused", "message": "Choose a meeting type." }, "durationMs": 12 } ], "timings": { "decide_ms": 480, "execute_ms": 12, "compose_ms": 260, "total_ms": 770 } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "test_id": { "type": "string", "minLength": 1, "description": "Keep the returned test_id for this temporary session. Expired sessions require a new test. [voice.StartVoiceTest](/developers/reference/voice/StartVoiceTest)." }, "utterance": { "type": "string", "minLength": 1, "description": "What the caller says." }, "history": { "type": "array", "items": { "type": "object", "properties": { "role": { "type": "string", "enum": [ "caller", "agent" ], "description": "Conversation speaker: caller is the simulated customer; agent is the assistant. This is not a workspace permission or member role." }, "text": { "type": "string", "description": "The words spoken by this participant, in conversation order." } }, "required": [ "role", "text" ], "additionalProperties": false }, "default": [], "description": "Earlier caller and assistant lines, oldest first. Omit or use [] for the first turn. Send accumulated conversation on later turns; the current utterance belongs only in utterance, not duplicated here." }, "turn_id": { "type": "string", "minLength": 1, "description": "Client-chosen identifier unique to one logical turn within this test. Keep it and the HTTP idempotency key unchanged when retrying that same utterance/history; choose new values for the next turn." } }, "required": [ "test_id", "utterance", "turn_id" ], "additionalProperties": false, "examples": [ { "test_id": "test_support_preview", "turn_id": "turn-1", "utterance": "I would like to book a meeting.", "history": [] } ] } ``` ```json-schema-response { "type": "object", "properties": { "text": { "type": "string", "description": "Assistant's reply to the current utterance. Display it and append it as an agent line to the next turn's history. Text alone does not prove a capability succeeded." }, "trace": { "type": "array", "description": "Ordered capability attempts for this turn, not a history of the whole test. [] means no capability was attempted. Entries are diagnostic JSON; the public contract does not fix their nested shape. See Inspect a test turn for how to read available diagnostics." }, "timings": { "description": "Server-side durations in milliseconds for this turn, not audio latency or client network time. These measurements are diagnostic, not a response-time guarantee.", "title": "RunVoiceTestTurnTimings", "type": "object", "properties": { "total_ms": { "type": "number", "description": "Elapsed duration of the turn-processing loop. May include overhead beyond the three component measurements." }, "decide_ms": { "type": "number", "description": "Time spent on the initial model decision before any capability execution." }, "execute_ms": { "type": "number", "description": "Total time spent executing or simulating the requested capabilities." }, "compose_ms": { "type": "number", "description": "Time spent on subsequent model calls after the initial decision, including follow-up decisions and composing a reply." } }, "required": [ "total_ms", "decide_ms", "execute_ms", "compose_ms" ], "additionalProperties": false } }, "required": [ "text" ], "additionalProperties": false, "examples": [ { "text": "What day and time work best for you?", "trace": [], "timings": { "decide_ms": 430, "execute_ms": 0, "compose_ms": 0, "total_ms": 447 } } ] } ``` --- # Start voice test Start a test call for a team inbox. Returns a test ID and an audio connection URL when available; text turns use voice.RunVoiceTestTurn. POST https://api.brigg.app/v1/operations/voice.StartVoiceTest ## Access & visibility Allow `voice.StartVoiceTest` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `inbox_id` | string | No | Inbox record ID from [List inboxes](/developers/reference/support/ListInboxes). Supply this when testing an inbox; use assistant: true instead for the acting member's own assistant. At least 1 character. | | `caller_id` | string or null | Yes | Person record ID to simulate a known caller, or null to test an unknown caller. Find a known caller with [List people](/developers/reference/customers/ListPeople). | | `selections` | array of [object](#request-selections) | No | Capabilities to test with, overriding the bound set. | ### request.selections[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `offering_key` | string | Yes | Stable key identifying a published voice capability. At least 1 character. | | `revision` | string | Yes | Revision identifying the version of this capability or configuration. At least 1 character. | | `settings` | [object](#request-selections-settings) | Yes | Configuration fields defined by this voice capability. | ### request.selections[].settings | Field | Type | Required | Description | | --- | --- | --- | --- | | `booking_link_id` | string | No | Booking link identifier. | ## Run a conversation test Start a test for the intended inbox and retain its `test_id`. Text clients can use [Run voice test turn](/developers/reference/voice/RunVoiceTestTurn); an audio connection URL is only needed for an audio client. Keep temporary connection URLs secret. Pass the simulated caller's utterance and previous conversation history in order. Keep a stable `turn_id` for a retried turn. Review the returned reply and capability trace; a simulated response is not evidence that a real customer call succeeded. [Review voice test](/developers/reference/voice/ReviewVoiceTest) accepts the conversation transcript for feedback. End the session when finished; an expired session needs a new start. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `test_id` | string | Yes | Names this test to voice.RunVoiceTestTurn, voice.ReviewVoiceTest and voice.EndVoiceTest. | | `expires` | number | Yes | Epoch ms after which the test is no longer accepted. | | `socket_url` | string or null | Yes | The audio socket URL, or null on a stage without an audio service. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [Run voice test turn](/developers/reference/voice/RunVoiceTestTurn) - [Review voice test](/developers/reference/voice/ReviewVoiceTest) - [End voice test](/developers/reference/voice/EndVoiceTest) - [List inboxes](/developers/reference/support/ListInboxes) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Test an unknown caller Choose a real inbox ID. A null socket_url still supports text turns. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/voice.StartVoiceTest' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "inbox_id": "e_inbox_support", "caller_id": null }' ``` #### TypeScript ```typescript 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/voice.StartVoiceTest", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "inbox_id": "e_inbox_support", "caller_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 = { "inbox_id": "e_inbox_support", "caller_id": None } request = Request( "https://api.brigg.app/v1/operations/voice.StartVoiceTest", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "test_id": "voice_test_kickoff", "expires": 1794301800000, "socket_url": null } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "inbox_id": { "type": "string", "minLength": 1, "description": "Inbox record ID from [List inboxes](/developers/reference/support/ListInboxes). Supply this when testing an inbox; use assistant: true instead for the acting member's own assistant." }, "caller_id": { "anyOf": [ { "type": "string", "minLength": 1, "description": "Person record ID to simulate a known caller, or null to test an unknown caller. Find a known caller with [List people](/developers/reference/customers/ListPeople)." }, { "type": "null", "description": "Person record ID to simulate a known caller, or null to test an unknown caller. Find a known caller with [List people](/developers/reference/customers/ListPeople)." } ], "description": "Person record ID to simulate a known caller, or null to test an unknown caller. Find a known caller with [List people](/developers/reference/customers/ListPeople)." }, "selections": { "type": "array", "items": { "type": "object", "properties": { "offering_key": { "type": "string", "minLength": 1, "description": "Stable key identifying a published voice capability." }, "revision": { "type": "string", "minLength": 1, "description": "Revision identifying the version of this capability or configuration." }, "settings": { "type": "object", "properties": { "booking_link_id": { "type": "string", "description": "Booking link identifier." } }, "additionalProperties": false, "description": "Configuration fields defined by this voice capability." } }, "required": [ "offering_key", "revision", "settings" ], "additionalProperties": false }, "description": "Capabilities to test with, overriding the bound set." } }, "required": [ "caller_id" ], "additionalProperties": false, "examples": [ { "inbox_id": "e_inbox_support", "caller_id": null } ] } ``` ```json-schema-response { "type": "object", "properties": { "test_id": { "type": "string", "description": "Names this test to voice.RunVoiceTestTurn, voice.ReviewVoiceTest and voice.EndVoiceTest." }, "expires": { "type": "number", "description": "Epoch ms after which the test is no longer accepted." }, "socket_url": { "type": [ "string", "null" ], "description": "The audio socket URL, or null on a stage without an audio service." } }, "required": [ "test_id", "expires", "socket_url" ], "additionalProperties": false, "examples": [ { "test_id": "voice_test_kickoff", "expires": 1794301800000, "socket_url": null } ] } ``` --- # Get site analytics breakdown Read a website's traffic grouped by page, source, campaign, country, device or another supported dimension for the selected dates. POST https://api.brigg.app/v1/operations/analytics.GetSiteAnalyticsBreakdown ## Access & visibility Allow `analytics.GetSiteAnalyticsBreakdown` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `bundle_id` | string | Yes | Select a website and use its content_id. This is the website identity, not a domain hostname or workspace ID. [workspace.ListBundles](/developers/reference/workspace/ListBundles). At least 1 character. | | `dimension` | string | Yes | Dimension used to group the traffic results. Allowed: `"page"`, `"entry_page"`, `"source"`, `"referrer"`, `"campaign"`, `"country"`, `"device"`, `"browser"`, `"os"`. | | `from` | integer | No | First UTC day, inclusive: floor(unixMilliseconds / 86400000). Defaults to 29 days before to. It is not a timestamp or date string. | | `to` | integer | No | Last UTC day, inclusive, as days since 1970-01-01. Defaults to today. If from is after to it becomes to; a difference above 366 is reduced to 366. Read the effective bounds in the response. | | `limit` | integer | No | Number of results to request per page. Range: 1 to 100. | ## Choose and interpret a reporting interval `from` and `to` are inclusive **UTC day indexes**, not dates or Unix milliseconds. For example, 1 October 2026 is `20727`. In JavaScript use `Math.floor(Date.parse("2026-10-01T00:00:00Z") / 86400000)`. Omitted `to` means today; omitted `from` means 29 days before `to`. The service clamps a span longer than 366 days. Read the response's `from` and `to` to see the interval actually used. `bounceRate` is a fraction, so `0.2` means 20%. Fields ending in `Ms` are durations in milliseconds. Summary visitors is the sum of daily visitor counts, not a deduplicated count of people across the interval. The same visitor can count on several days; workspace totals also sum across sites. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `bundle_id` | string | Yes | Bundle identifier. | | `dimension` | string | Yes | Dimension used to group the traffic results. | | `from` | number | Yes | First UTC day in the reporting interval, inclusive. A day index counts days since 1970-01-01; multiply by 86400000 to obtain Unix milliseconds. | | `to` | number | Yes | Last UTC day in the reporting interval, inclusive, as a day index since 1970-01-01. | | `rows` | array of [object](#response-rows) | Yes | Traffic measurements grouped by the requested dimension. | ### response.rows[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `value` | string | Yes | Value of the grouping dimension for this row. | | `pageviews` | number | Yes | Pageviews for this dimension value, except entry_page where it counts session landings. | | `visitors` | number | Yes | Sum of daily distinct visitors per site. A person returning on another day or site can be counted again; this is not a deduplicated multi-day audience. | | `avg_engagement_ms` | number | Yes | Avg engagement ms, in milliseconds. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [Get site analytics summary](/developers/reference/analytics/GetSiteAnalyticsSummary) - [Get site analytics realtime](/developers/reference/analytics/GetSiteAnalyticsRealtime) - [List bundles](/developers/reference/workspace/ListBundles) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/analytics.GetSiteAnalyticsBreakdown' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "bundle_id": "e_example", "dimension": "page" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/analytics.GetSiteAnalyticsBreakdown", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "bundle_id": "e_example", "dimension": "page" }), }); 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 payload = { "bundle_id": "e_example", "dimension": "page" } request = Request( "https://api.brigg.app/v1/operations/analytics.GetSiteAnalyticsBreakdown", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "bundle_id": "e_example", "dimension": "page", "from": 20727, "to": 20728, "rows": [ { "value": "/pricing", "pageviews": 55, "visitors": 32, "avg_engagement_ms": 1 } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "bundle_id": { "type": "string", "minLength": 1, "description": "Select a website and use its content_id. This is the website identity, not a domain hostname or workspace ID. [workspace.ListBundles](/developers/reference/workspace/ListBundles)." }, "dimension": { "type": "string", "enum": [ "page", "entry_page", "source", "referrer", "campaign", "country", "device", "browser", "os" ], "description": "Dimension used to group the traffic results." }, "from": { "type": "integer", "description": "First UTC day, inclusive: floor(unixMilliseconds / 86400000). Defaults to 29 days before to. It is not a timestamp or date string." }, "to": { "type": "integer", "description": "Last UTC day, inclusive, as days since 1970-01-01. Defaults to today. If from is after to it becomes to; a difference above 366 is reduced to 366. Read the effective bounds in the response." }, "limit": { "type": "integer", "minimum": 1, "maximum": 100, "description": "Number of results to request per page." } }, "required": [ "bundle_id", "dimension" ], "additionalProperties": false, "examples": [ { "bundle_id": "e_example", "dimension": "page" } ] } ``` ```json-schema-response { "type": "object", "properties": { "bundle_id": { "type": "string", "description": "Bundle identifier." }, "dimension": { "type": "string", "description": "Dimension used to group the traffic results." }, "from": { "type": "number", "description": "First UTC day in the reporting interval, inclusive. A day index counts days since 1970-01-01; multiply by 86400000 to obtain Unix milliseconds." }, "to": { "type": "number", "description": "Last UTC day in the reporting interval, inclusive, as a day index since 1970-01-01." }, "rows": { "type": "array", "items": { "type": "object", "properties": { "value": { "type": "string", "description": "Value of the grouping dimension for this row." }, "pageviews": { "type": "number", "description": "Pageviews for this dimension value, except entry_page where it counts session landings." }, "visitors": { "type": "number", "description": "Sum of daily distinct visitors per site. A person returning on another day or site can be counted again; this is not a deduplicated multi-day audience." }, "avg_engagement_ms": { "type": "number", "description": "Avg engagement ms, in milliseconds." } }, "required": [ "value", "pageviews", "visitors", "avg_engagement_ms" ], "additionalProperties": false }, "description": "Traffic measurements grouped by the requested dimension." } }, "required": [ "bundle_id", "dimension", "from", "to", "rows" ], "additionalProperties": false, "examples": [ { "bundle_id": "e_example", "dimension": "page", "from": 20727, "to": 20728, "rows": [ { "value": "/pricing", "pageviews": 55, "visitors": 32, "avg_engagement_ms": 1 } ] } ] } ``` --- # Get site analytics realtime Read the number of distinct recent visitors to a hosted website. window_ms identifies the time interval covered. POST https://api.brigg.app/v1/operations/analytics.GetSiteAnalyticsRealtime ## Access & visibility Allow `analytics.GetSiteAnalyticsRealtime` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `bundle_id` | string | Yes | Select a website and use its content_id. This is the website identity, not a domain hostname or workspace ID. [workspace.ListBundles](/developers/reference/workspace/ListBundles). At least 1 character. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `bundle_id` | string | Yes | Bundle identifier. | | `visitors` | number | Yes | Distinct visitors during the recent window_ms interval. Unlike multi-day summaries, this is deduplicated within that live window. | | `window_ms` | number | Yes | Window ms, in milliseconds. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [List bundles](/developers/reference/workspace/ListBundles) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/analytics.GetSiteAnalyticsRealtime' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "bundle_id": "e_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/analytics.GetSiteAnalyticsRealtime", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "bundle_id": "e_example" }), }); 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 payload = { "bundle_id": "e_example" } request = Request( "https://api.brigg.app/v1/operations/analytics.GetSiteAnalyticsRealtime", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "bundle_id": "e_example", "visitors": 12, "window_ms": 300000 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "bundle_id": { "type": "string", "minLength": 1, "description": "Select a website and use its content_id. This is the website identity, not a domain hostname or workspace ID. [workspace.ListBundles](/developers/reference/workspace/ListBundles)." } }, "required": [ "bundle_id" ], "additionalProperties": false, "examples": [ { "bundle_id": "e_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "bundle_id": { "type": "string", "description": "Bundle identifier." }, "visitors": { "type": "number", "description": "Distinct visitors during the recent window_ms interval. Unlike multi-day summaries, this is deduplicated within that live window." }, "window_ms": { "type": "number", "description": "Window ms, in milliseconds." } }, "required": [ "bundle_id", "visitors", "window_ms" ], "additionalProperties": false, "examples": [ { "bundle_id": "e_example", "visitors": 12, "window_ms": 300000 } ] } ``` --- # Get site analytics summary Read a hosted website's traffic totals and trends for the selected dates. POST https://api.brigg.app/v1/operations/analytics.GetSiteAnalyticsSummary ## Access & visibility Allow `analytics.GetSiteAnalyticsSummary` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `bundle_id` | string | Yes | Select a website and use its content_id. This is the website identity, not a domain hostname or workspace ID. [workspace.ListBundles](/developers/reference/workspace/ListBundles). At least 1 character. | | `from` | integer | No | First UTC day, inclusive: floor(unixMilliseconds / 86400000). Defaults to 29 days before to. It is not a timestamp or date string. | | `to` | integer | No | Last UTC day, inclusive, as days since 1970-01-01. Defaults to today. If from is after to it becomes to; a difference above 366 is reduced to 366. Read the effective bounds in the response. | ## Choose and interpret a reporting interval `from` and `to` are inclusive **UTC day indexes**, not dates or Unix milliseconds. For example, 1 October 2026 is `20727`. In JavaScript use `Math.floor(Date.parse("2026-10-01T00:00:00Z") / 86400000)`. Omitted `to` means today; omitted `from` means 29 days before `to`. The service clamps a span longer than 366 days. Read the response's `from` and `to` to see the interval actually used. `bounce_rate` is a fraction, so `0.2` means 20%. Fields ending in `Ms` are durations in milliseconds. Summary visitors is the sum of daily visitor counts, not a deduplicated count of people across the interval. The same visitor can count on several days; workspace totals also sum across sites. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `bundle_id` | string | Yes | Bundle identifier. | | `from` | number | Yes | First UTC day in the reporting interval, inclusive. A day index counts days since 1970-01-01; multiply by 86400000 to obtain Unix milliseconds. | | `to` | number | Yes | Last UTC day in the reporting interval, inclusive, as a day index since 1970-01-01. | | `series` | array of [object](#response-series) | Yes | Available daily buckets in ascending UTC-day order. Dates without activity are omitted; insert zeros in your chart when a continuous date axis is needed. | | `pageviews` | number | Yes | Total pageview events in the effective interval. | | `visitors` | number | Yes | Sum of daily distinct visitors per site. A person returning on another day or site can be counted again; this is not a deduplicated multi-day audience. | | `sessions` | number | Yes | Visits, separated by an inactivity gap of at least 30 minutes. A visit crossing midnight is attributed to its starting day. | | `bounces` | number | Yes | Sessions containing a single pageview. | | `bounce_rate` | number | Yes | bounces divided by sessions, from 0 to 1; 0 when sessions is zero. Multiply by 100 for a percentage. | | `avg_visit_ms` | number | Yes | Total session duration divided by sessions, rounded to milliseconds; 0 when there are no sessions. | | `avg_engagement_ms` | number | Yes | Total active-page time divided by pageviews, rounded to milliseconds; 0 when there are no pageviews. This is per pageview, not per session. | ### response.series[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `day` | number | Yes | UTC day for this reporting bucket, as days since 1970-01-01, not Unix milliseconds. | | `pageviews` | number | Yes | Pageviews whose event time falls on this UTC day. | | `visitors` | number | Yes | Distinct visitors within this UTC day and site; workspace series sums the per-site counts. | | `sessions` | number | Yes | Sessions beginning on this UTC day. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [Get site analytics breakdown](/developers/reference/analytics/GetSiteAnalyticsBreakdown) - [Get site analytics realtime](/developers/reference/analytics/GetSiteAnalyticsRealtime) - [List bundles](/developers/reference/workspace/ListBundles) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Read two complete UTC days 20727 and 20728 are UTC day indices. The two buckets sum to the displayed counts; visitors is not deduplicated across days. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/analytics.GetSiteAnalyticsSummary' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "bundle_id": "c_company_site", "from": 20727, "to": 20728 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/analytics.GetSiteAnalyticsSummary", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "bundle_id": "c_company_site", "from": 20727, "to": 20728 }), }); 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 payload = { "bundle_id": "c_company_site", "from": 20727, "to": 20728 } request = Request( "https://api.brigg.app/v1/operations/analytics.GetSiteAnalyticsSummary", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "from": 20727, "to": 20728, "series": [ { "day": 20727, "pageviews": 80, "visitors": 40, "sessions": 50 }, { "day": 20728, "pageviews": 40, "visitors": 20, "sessions": 25 } ], "pageviews": 120, "visitors": 60, "sessions": 75, "bounces": 15, "bounce_rate": 0.2, "avg_visit_ms": 120000, "avg_engagement_ms": 60000, "bundle_id": "c_company_site" } ``` ### No activity in the interval An empty series means no buckets were recorded. It is not an authorization failure. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/analytics.GetSiteAnalyticsSummary' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "bundle_id": "c_company_site", "from": 20727, "to": 20728 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/analytics.GetSiteAnalyticsSummary", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "bundle_id": "c_company_site", "from": 20727, "to": 20728 }), }); 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 payload = { "bundle_id": "c_company_site", "from": 20727, "to": 20728 } request = Request( "https://api.brigg.app/v1/operations/analytics.GetSiteAnalyticsSummary", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "from": 20727, "to": 20728, "series": [], "pageviews": 0, "visitors": 0, "sessions": 0, "bounces": 0, "bounce_rate": 0, "avg_visit_ms": 0, "avg_engagement_ms": 0, "bundle_id": "c_company_site" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "bundle_id": { "type": "string", "minLength": 1, "description": "Select a website and use its content_id. This is the website identity, not a domain hostname or workspace ID. [workspace.ListBundles](/developers/reference/workspace/ListBundles)." }, "from": { "type": "integer", "description": "First UTC day, inclusive: floor(unixMilliseconds / 86400000). Defaults to 29 days before to. It is not a timestamp or date string." }, "to": { "type": "integer", "description": "Last UTC day, inclusive, as days since 1970-01-01. Defaults to today. If from is after to it becomes to; a difference above 366 is reduced to 366. Read the effective bounds in the response." } }, "required": [ "bundle_id" ], "additionalProperties": false, "examples": [ { "bundle_id": "c_company_site", "from": 20727, "to": 20728 } ] } ``` ```json-schema-response { "type": "object", "properties": { "bundle_id": { "type": "string", "description": "Bundle identifier." }, "from": { "type": "number", "description": "First UTC day in the reporting interval, inclusive. A day index counts days since 1970-01-01; multiply by 86400000 to obtain Unix milliseconds." }, "to": { "type": "number", "description": "Last UTC day in the reporting interval, inclusive, as a day index since 1970-01-01." }, "series": { "type": "array", "items": { "type": "object", "properties": { "day": { "type": "number", "description": "UTC day for this reporting bucket, as days since 1970-01-01, not Unix milliseconds." }, "pageviews": { "type": "number", "description": "Pageviews whose event time falls on this UTC day." }, "visitors": { "type": "number", "description": "Distinct visitors within this UTC day and site; workspace series sums the per-site counts." }, "sessions": { "type": "number", "description": "Sessions beginning on this UTC day." } }, "required": [ "day", "pageviews", "visitors", "sessions" ], "additionalProperties": false }, "description": "Available daily buckets in ascending UTC-day order. Dates without activity are omitted; insert zeros in your chart when a continuous date axis is needed." }, "pageviews": { "type": "number", "description": "Total pageview events in the effective interval." }, "visitors": { "type": "number", "description": "Sum of daily distinct visitors per site. A person returning on another day or site can be counted again; this is not a deduplicated multi-day audience." }, "sessions": { "type": "number", "description": "Visits, separated by an inactivity gap of at least 30 minutes. A visit crossing midnight is attributed to its starting day." }, "bounces": { "type": "number", "description": "Sessions containing a single pageview." }, "bounce_rate": { "type": "number", "description": "bounces divided by sessions, from 0 to 1; 0 when sessions is zero. Multiply by 100 for a percentage." }, "avg_visit_ms": { "type": "number", "description": "Total session duration divided by sessions, rounded to milliseconds; 0 when there are no sessions." }, "avg_engagement_ms": { "type": "number", "description": "Total active-page time divided by pageviews, rounded to milliseconds; 0 when there are no pageviews. This is per pageview, not per session." } }, "required": [ "bundle_id", "from", "to", "series", "pageviews", "visitors", "sessions", "bounces", "bounce_rate", "avg_visit_ms", "avg_engagement_ms" ], "additionalProperties": false, "examples": [ { "from": 20727, "to": 20728, "series": [ { "day": 20727, "pageviews": 80, "visitors": 40, "sessions": 50 }, { "day": 20728, "pageviews": 40, "visitors": 20, "sessions": 25 } ], "pageviews": 120, "visitors": 60, "sessions": 75, "bounces": 15, "bounce_rate": 0.2, "avg_visit_ms": 120000, "avg_engagement_ms": 60000, "bundle_id": "c_company_site" } ] } ``` --- # Get workspace analytics summary Read traffic totals across the workspace's hosted websites for the selected dates. POST https://api.brigg.app/v1/operations/analytics.GetWorkspaceAnalyticsSummary ## Access & visibility Allow `analytics.GetWorkspaceAnalyticsSummary` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `from` | integer | No | First UTC day, inclusive: floor(unixMilliseconds / 86400000). Defaults to 29 days before to. It is not a timestamp or date string. | | `to` | integer | No | Last UTC day, inclusive, as days since 1970-01-01. Defaults to today. If from is after to it becomes to; a difference above 366 is reduced to 366. Read the effective bounds in the response. | ## Choose and interpret a reporting interval `from` and `to` are inclusive **UTC day indexes**, not dates or Unix milliseconds. For example, 1 October 2026 is `20727`. In JavaScript use `Math.floor(Date.parse("2026-10-01T00:00:00Z") / 86400000)`. Omitted `to` means today; omitted `from` means 29 days before `to`. The service clamps a span longer than 366 days. Read the response's `from` and `to` to see the interval actually used. `bounce_rate` is a fraction, so `0.2` means 20%. Fields ending in `Ms` are durations in milliseconds. Summary visitors is the sum of daily visitor counts, not a deduplicated count of people across the interval. The same visitor can count on several days; workspace totals also sum across sites. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `from` | number | Yes | First UTC day in the reporting interval, inclusive. A day index counts days since 1970-01-01; multiply by 86400000 to obtain Unix milliseconds. | | `to` | number | Yes | Last UTC day in the reporting interval, inclusive, as a day index since 1970-01-01. | | `series` | array of [object](#response-series) | Yes | Available daily buckets in ascending UTC-day order. Dates without activity are omitted; insert zeros in your chart when a continuous date axis is needed. | | `pageviews` | number | Yes | Total pageview events in the effective interval. | | `visitors` | number | Yes | Sum of daily distinct visitors per site. A person returning on another day or site can be counted again; this is not a deduplicated multi-day audience. | | `sessions` | number | Yes | Visits, separated by an inactivity gap of at least 30 minutes. A visit crossing midnight is attributed to its starting day. | | `bounces` | number | Yes | Sessions containing a single pageview. | | `bounce_rate` | number | Yes | bounces divided by sessions, from 0 to 1; 0 when sessions is zero. Multiply by 100 for a percentage. | | `avg_visit_ms` | number | Yes | Total session duration divided by sessions, rounded to milliseconds; 0 when there are no sessions. | | `avg_engagement_ms` | number | Yes | Total active-page time divided by pageviews, rounded to milliseconds; 0 when there are no pageviews. This is per pageview, not per session. | | `bundles` | array of [object](#response-bundles) | Yes | Websites contributing to these workspace totals. | ### response.series[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `day` | number | Yes | UTC day for this reporting bucket, as days since 1970-01-01, not Unix milliseconds. | | `pageviews` | number | Yes | Pageviews whose event time falls on this UTC day. | | `visitors` | number | Yes | Distinct visitors within this UTC day and site; workspace series sums the per-site counts. | | `sessions` | number | Yes | Sessions beginning on this UTC day. | ### response.bundles[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `bundle_id` | string | Yes | Website bundle ID. Use it as bundle_id for the site-specific analytics operations. | | `pageviews` | number | Yes | Total pageview events in the effective interval. | | `visitors` | number | Yes | Sum of daily distinct visitors per site. A person returning on another day or site can be counted again; this is not a deduplicated multi-day audience. | | `sessions` | number | Yes | Visits, separated by an inactivity gap of at least 30 minutes. A visit crossing midnight is attributed to its starting day. | | `bounces` | number | Yes | Sessions containing a single pageview. | | `bounce_rate` | number | Yes | bounces divided by sessions, from 0 to 1; 0 when sessions is zero. Multiply by 100 for a percentage. | | `avg_visit_ms` | number | Yes | Total session duration divided by sessions, rounded to milliseconds; 0 when there are no sessions. | | `avg_engagement_ms` | number | Yes | Total active-page time divided by pageviews, rounded to milliseconds; 0 when there are no pageviews. This is per pageview, not per session. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [Get site analytics summary](/developers/reference/analytics/GetSiteAnalyticsSummary) - [Get site analytics breakdown](/developers/reference/analytics/GetSiteAnalyticsBreakdown) - [Get site analytics realtime](/developers/reference/analytics/GetSiteAnalyticsRealtime) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Read two complete UTC days 20727 and 20728 are UTC day indices. The two buckets sum to the displayed counts; visitors is not deduplicated across days. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/analytics.GetWorkspaceAnalyticsSummary' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "from": 20727, "to": 20728 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/analytics.GetWorkspaceAnalyticsSummary", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "from": 20727, "to": 20728 }), }); 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 payload = { "from": 20727, "to": 20728 } request = Request( "https://api.brigg.app/v1/operations/analytics.GetWorkspaceAnalyticsSummary", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "from": 20727, "to": 20728, "series": [ { "day": 20727, "pageviews": 80, "visitors": 40, "sessions": 50 }, { "day": 20728, "pageviews": 40, "visitors": 20, "sessions": 25 } ], "pageviews": 120, "visitors": 60, "sessions": 75, "bounces": 15, "bounce_rate": 0.2, "avg_visit_ms": 120000, "avg_engagement_ms": 60000, "bundles": [ { "bundle_id": "c_company_site", "pageviews": 120, "visitors": 60, "sessions": 75, "bounces": 15, "bounce_rate": 0.2, "avg_visit_ms": 120000, "avg_engagement_ms": 60000 } ] } ``` ### No activity in the interval An empty series means no buckets were recorded. It is not an authorization failure. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/analytics.GetWorkspaceAnalyticsSummary' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "from": 20727, "to": 20728 }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/analytics.GetWorkspaceAnalyticsSummary", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "from": 20727, "to": 20728 }), }); 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 payload = { "from": 20727, "to": 20728 } request = Request( "https://api.brigg.app/v1/operations/analytics.GetWorkspaceAnalyticsSummary", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "from": 20727, "to": 20728, "series": [], "pageviews": 0, "visitors": 0, "sessions": 0, "bounces": 0, "bounce_rate": 0, "avg_visit_ms": 0, "avg_engagement_ms": 0, "bundles": [] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "from": { "type": "integer", "description": "First UTC day, inclusive: floor(unixMilliseconds / 86400000). Defaults to 29 days before to. It is not a timestamp or date string." }, "to": { "type": "integer", "description": "Last UTC day, inclusive, as days since 1970-01-01. Defaults to today. If from is after to it becomes to; a difference above 366 is reduced to 366. Read the effective bounds in the response." } }, "additionalProperties": false, "examples": [ { "from": 20727, "to": 20728 } ] } ``` ```json-schema-response { "type": "object", "properties": { "from": { "type": "number", "description": "First UTC day in the reporting interval, inclusive. A day index counts days since 1970-01-01; multiply by 86400000 to obtain Unix milliseconds." }, "to": { "type": "number", "description": "Last UTC day in the reporting interval, inclusive, as a day index since 1970-01-01." }, "series": { "type": "array", "items": { "type": "object", "properties": { "day": { "type": "number", "description": "UTC day for this reporting bucket, as days since 1970-01-01, not Unix milliseconds." }, "pageviews": { "type": "number", "description": "Pageviews whose event time falls on this UTC day." }, "visitors": { "type": "number", "description": "Distinct visitors within this UTC day and site; workspace series sums the per-site counts." }, "sessions": { "type": "number", "description": "Sessions beginning on this UTC day." } }, "required": [ "day", "pageviews", "visitors", "sessions" ], "additionalProperties": false }, "description": "Available daily buckets in ascending UTC-day order. Dates without activity are omitted; insert zeros in your chart when a continuous date axis is needed." }, "pageviews": { "type": "number", "description": "Total pageview events in the effective interval." }, "visitors": { "type": "number", "description": "Sum of daily distinct visitors per site. A person returning on another day or site can be counted again; this is not a deduplicated multi-day audience." }, "sessions": { "type": "number", "description": "Visits, separated by an inactivity gap of at least 30 minutes. A visit crossing midnight is attributed to its starting day." }, "bounces": { "type": "number", "description": "Sessions containing a single pageview." }, "bounce_rate": { "type": "number", "description": "bounces divided by sessions, from 0 to 1; 0 when sessions is zero. Multiply by 100 for a percentage." }, "avg_visit_ms": { "type": "number", "description": "Total session duration divided by sessions, rounded to milliseconds; 0 when there are no sessions." }, "avg_engagement_ms": { "type": "number", "description": "Total active-page time divided by pageviews, rounded to milliseconds; 0 when there are no pageviews. This is per pageview, not per session." }, "bundles": { "type": "array", "items": { "type": "object", "properties": { "bundle_id": { "type": "string", "description": "Website bundle ID. Use it as bundle_id for the site-specific analytics operations." }, "pageviews": { "type": "number", "description": "Total pageview events in the effective interval." }, "visitors": { "type": "number", "description": "Sum of daily distinct visitors per site. A person returning on another day or site can be counted again; this is not a deduplicated multi-day audience." }, "sessions": { "type": "number", "description": "Visits, separated by an inactivity gap of at least 30 minutes. A visit crossing midnight is attributed to its starting day." }, "bounces": { "type": "number", "description": "Sessions containing a single pageview." }, "bounce_rate": { "type": "number", "description": "bounces divided by sessions, from 0 to 1; 0 when sessions is zero. Multiply by 100 for a percentage." }, "avg_visit_ms": { "type": "number", "description": "Total session duration divided by sessions, rounded to milliseconds; 0 when there are no sessions." }, "avg_engagement_ms": { "type": "number", "description": "Total active-page time divided by pageviews, rounded to milliseconds; 0 when there are no pageviews. This is per pageview, not per session." } }, "required": [ "bundle_id", "pageviews", "visitors", "sessions", "bounces", "bounce_rate", "avg_visit_ms", "avg_engagement_ms" ], "additionalProperties": false }, "description": "Websites contributing to these workspace totals." } }, "required": [ "from", "to", "series", "pageviews", "visitors", "sessions", "bounces", "bounce_rate", "avg_visit_ms", "avg_engagement_ms", "bundles" ], "additionalProperties": false, "examples": [ { "from": 20727, "to": 20728, "series": [ { "day": 20727, "pageviews": 80, "visitors": 40, "sessions": 50 }, { "day": 20728, "pageviews": 40, "visitors": 20, "sessions": 25 } ], "pageviews": 120, "visitors": 60, "sessions": 75, "bounces": 15, "bounce_rate": 0.2, "avg_visit_ms": 120000, "avg_engagement_ms": 60000, "bundles": [ { "bundle_id": "c_company_site", "pageviews": 120, "visitors": 60, "sessions": 75, "bounces": 15, "bounce_rate": 0.2, "avg_visit_ms": 120000, "avg_engagement_ms": 60000 } ] } ] } ``` --- # List webhook deliveries Inspect webhook delivery attempts, outcomes and errors. Signing secrets and payload contents are excluded. POST https://api.brigg.app/v1/operations/webhooks.ListWebhookDeliveries ## Access & visibility Allow `webhooks.ListWebhookDeliveries` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `webhook_id` | string | Yes | Identifier of the approved webhook subscription. After administrator approval, discover it with `webhooks.ListWebhookSubscriptions` using a credential with read access to every selected resource type. It is different from an event ID or delivery ID. At least 1 character. | | `cursor` | string | No | Opaque next_cursor returned by this webhook's preceding page. Keep the same webhook and credential; omit it to start a new listing. | | `limit` | integer | No | Maximum number of results to return in this page. Continue with next_cursor when returned. Default: `50`. Range: 1 to 100. | ## Response Returns **200 OK** with a JSON body. An empty `items` array means this page contains no matching visible results. Follow `next_cursor` when present. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [Webhook delivery](#webhook-delivery-response-items) | Yes | Delivery attempts for the selected webhook, within the retained delivery history. Pass next_cursor as cursor to continue when a next cursor is returned. | | `next_cursor` | string | No | Continue this webhook's listing with this value as cursor. Omitted on the final page. | ### Webhook delivery · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `delivery_id` | string | Yes | Delivery identifier returned by `webhooks.ListWebhookDeliveries`. Replay uses this identifier for the same webhook; active deliveries cannot be replayed. | | `event_id` | string | Yes | Stable event identifier. Deduplicate notifications by this value, including retries and deliberate replays. | | `event` | string | Yes | Event name. Supported values: `meeting.completed`, `resource.created`, `resource.updated`, `resource.deleted`. See the [event reference](/developers/events) for payloads and delivery contracts. | | `resource_type` | string | Yes | Record type associated with this event, such as core:Company. | | `status` | string | Yes | Delivery state recorded by the delivery worker. Check last_status and last_error when delivery fails. | | `attempts` | number | Yes | Number of delivery attempts made so far for this event and subscription. | | `last_status` | number or null | Yes | HTTP status of the most recent endpoint response, or null if no HTTP response was received. | | `last_error` | string or null | Yes | Most recently recorded delivery error, or null if none was recorded. | | `created_at` | number | Yes | Creation time in Unix milliseconds. | | `updated_at` | number | Yes | Last update time in Unix milliseconds. | ## Pagination Pass `next_cursor` as `cursor` on the next request, keeping the same query and acting identity. Stop when `next_cursor` is absent. Treat the cursor as opaque; never construct or edit it. ```typescript const query = { "webhook_id": "e_example" }; let cursor; do { const response = await fetch("https://api.brigg.app/v1/operations/webhooks.ListWebhookDeliveries", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ ...query, ...(cursor ? { cursor } : {}) }), }); const page = await response.json(); if (!response.ok) throw new Error(`${response.status}: ${page.message}`); for (const item of page.items) { console.log(item); // Process or upsert each result. } cursor = page.next_cursor; } while (cursor); ``` ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [Receive and verify webhooks](/developers/webhooks) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/webhooks.ListWebhookDeliveries' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "webhook_id": "e_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/webhooks.ListWebhookDeliveries", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "webhook_id": "e_example" }), }); 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 payload = { "webhook_id": "e_example" } request = Request( "https://api.brigg.app/v1/operations/webhooks.ListWebhookDeliveries", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "delivery_id": "delivery_company_123", "event_id": "event_company_123", "event": "resource.updated", "resource_type": "core:Company", "status": "delivered", "attempts": 1, "last_status": 200, "last_error": null, "created_at": 1794301200000, "updated_at": 1794301200000 } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "webhook_id": { "type": "string", "minLength": 1, "description": "Identifier of the approved webhook subscription. After administrator approval, discover it with `webhooks.ListWebhookSubscriptions` using a credential with read access to every selected resource type. It is different from an event ID or delivery ID." }, "cursor": { "type": "string", "description": "Opaque next_cursor returned by this webhook's preceding page. Keep the same webhook and credential; omit it to start a new listing." }, "limit": { "type": "integer", "minimum": 1, "maximum": 100, "default": 50, "description": "Maximum number of results to return in this page. Continue with next_cursor when returned." } }, "required": [ "webhook_id" ], "additionalProperties": false, "examples": [ { "webhook_id": "e_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "delivery_id": { "type": "string", "description": "Delivery identifier returned by `webhooks.ListWebhookDeliveries`. Replay uses this identifier for the same webhook; active deliveries cannot be replayed.", "examples": [ "delivery_company_123" ] }, "event_id": { "type": "string", "description": "Stable event identifier. Deduplicate notifications by this value, including retries and deliberate replays.", "examples": [ "event_company_123" ] }, "event": { "type": "string", "description": "Event name. Supported values: `meeting.completed`, `resource.created`, `resource.updated`, `resource.deleted`. See the [event reference](/developers/events) for payloads and delivery contracts.", "examples": [ "resource.updated" ] }, "resource_type": { "type": "string", "description": "Record type associated with this event, such as core:Company.", "examples": [ "core:Company" ] }, "status": { "type": "string", "description": "Delivery state recorded by the delivery worker. Check last_status and last_error when delivery fails.", "examples": [ "delivered" ] }, "attempts": { "type": "number", "description": "Number of delivery attempts made so far for this event and subscription.", "examples": [ 1 ] }, "last_status": { "type": [ "number", "null" ], "description": "HTTP status of the most recent endpoint response, or null if no HTTP response was received.", "examples": [ 200 ] }, "last_error": { "type": [ "string", "null" ], "description": "Most recently recorded delivery error, or null if none was recorded.", "examples": [ null ] }, "created_at": { "type": "number", "description": "Creation time in Unix milliseconds." }, "updated_at": { "type": "number", "description": "Last update time in Unix milliseconds." } }, "required": [ "delivery_id", "event_id", "event", "resource_type", "status", "attempts", "last_status", "last_error", "created_at", "updated_at" ], "additionalProperties": false, "title": "Webhook delivery" }, "description": "Delivery attempts for the selected webhook, within the retained delivery history. Pass next_cursor as cursor to continue when a next cursor is returned." }, "next_cursor": { "type": "string", "description": "Continue this webhook's listing with this value as cursor. Omitted on the final page." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "delivery_id": "delivery_company_123", "event_id": "event_company_123", "event": "resource.updated", "resource_type": "core:Company", "status": "delivered", "attempts": 1, "last_status": 200, "last_error": null, "created_at": 1794301200000, "updated_at": 1794301200000 } ] } ] } ``` --- # Replay webhook delivery Retry a completed or failed webhook delivery using its original event and delivery IDs. Receivers must deduplicate by event_id. Active deliveries cannot be replayed. POST https://api.brigg.app/v1/operations/webhooks.ReplayWebhookDelivery ## Access & visibility Allow `webhooks.ReplayWebhookDelivery` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `webhook_id` | string | Yes | Identifier of the approved webhook subscription. After administrator approval, discover it with `webhooks.ListWebhookSubscriptions` using a credential with read access to every selected resource type. It is different from an event ID or delivery ID. At least 1 character. | | `delivery_id` | string | Yes | Delivery identifier returned by `webhooks.ListWebhookDeliveries`. Replay uses this identifier for the same webhook; active deliveries cannot be replayed. At least 1 character. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `delivery_id` | string | Yes | Delivery identifier returned by `webhooks.ListWebhookDeliveries`. Replay uses this identifier for the same webhook; active deliveries cannot be replayed. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [Receive and verify webhooks](/developers/webhooks) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/webhooks.ReplayWebhookDelivery' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "webhook_id": "e_example", "delivery_id": "e_example" }' ``` #### TypeScript ```typescript 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/webhooks.ReplayWebhookDelivery", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "webhook_id": "e_example", "delivery_id": "e_example" }), }); 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 = { "webhook_id": "e_example", "delivery_id": "e_example" } request = Request( "https://api.brigg.app/v1/operations/webhooks.ReplayWebhookDelivery", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "delivery_id": "e_example" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "webhook_id": { "type": "string", "minLength": 1, "description": "Identifier of the approved webhook subscription. After administrator approval, discover it with `webhooks.ListWebhookSubscriptions` using a credential with read access to every selected resource type. It is different from an event ID or delivery ID." }, "delivery_id": { "type": "string", "minLength": 1, "description": "Delivery identifier returned by `webhooks.ListWebhookDeliveries`. Replay uses this identifier for the same webhook; active deliveries cannot be replayed." } }, "required": [ "webhook_id", "delivery_id" ], "additionalProperties": false, "examples": [ { "webhook_id": "e_example", "delivery_id": "e_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "delivery_id": { "type": "string", "description": "Delivery identifier returned by `webhooks.ListWebhookDeliveries`. Replay uses this identifier for the same webhook; active deliveries cannot be replayed." } }, "required": [ "delivery_id" ], "additionalProperties": false, "examples": [ { "delivery_id": "e_example" } ] } ``` --- # List webhook events Read retained events for an approved shared webhook. Events remain available for 30 days; the current subscription and resource permissions are checked on every call. POST https://api.brigg.app/v1/operations/webhooks.ListWebhookEvents ## Access & visibility Allow `webhooks.ListWebhookEvents` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `webhook_id` | string | Yes | Identifier of the approved webhook subscription. After administrator approval, discover it with `webhooks.ListWebhookSubscriptions` using a credential with read access to every selected resource type. It is different from an event ID or delivery ID. At least 1 character. | | `cursor` | string | No | Opaque next_cursor returned by this webhook's preceding page. Keep the same webhook and credential; omit it to start a new listing. | | `limit` | integer | No | Maximum number of results to return in this page. Continue with next_cursor when returned. Default: `50`. Range: 1 to 100. | | `since` | integer | No | Earliest event creation time to return, in Unix milliseconds. Recovery is limited to the 30-day retention window. Minimum: 0. | ## Response Returns **200 OK** with a JSON body. An empty `items` array means this page contains no matching visible results. Follow `next_cursor` when present. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [Webhook event](#webhook-event-response-items) | Yes | Recoverable events for the selected webhook, within the 30-day retention window. Pass next_cursor as cursor to continue when a next cursor is returned. | | `next_cursor` | string | No | Continue this webhook's listing with this value as cursor. Omitted on the final page. | ### Webhook event · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `event_id` | string | Yes | Stable event identifier. Deduplicate notifications by this value, including retries and deliberate replays. | | `event` | string | Yes | Event name. Supported values: `meeting.completed`, `resource.created`, `resource.updated`, `resource.deleted`. See the [event reference](/developers/events) for payloads and delivery contracts. Allowed: `"resource.created"`, `"resource.updated"`, `"resource.deleted"`. | | `version` | string | Yes | Payload contract version used to serialize this event. Always `"v1"`. | | `occurred_at` | string | Yes | Event creation time in Unix milliseconds. Format: date-time. | | `resource` | [object](#response-items-resource) | Yes | Affected record's type and ID; the event does not include the record's complete contents. | | `changed_fields` | array of string | No | Names of fields changed by an update, when supplied. Fetch the record to read its current values. | | `test` | boolean | No | Whether this is a synthetic test event rather than a real resource change. Always `true`. | ### response.items[].resource | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Unique identifier. Use the value returned by a create or list operation. | | `type` | string | Yes | Type identifying which variant of this model applies. | | `version` | string | Yes | Opaque resource revision. Events may arrive out of order. | ## Pagination Pass `next_cursor` as `cursor` on the next request, keeping the same query and acting identity. Stop when `next_cursor` is absent. Treat the cursor as opaque; never construct or edit it. ```typescript const query = { "webhook_id": "e_example" }; let cursor; do { const response = await fetch("https://api.brigg.app/v1/operations/webhooks.ListWebhookEvents", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ ...query, ...(cursor ? { cursor } : {}) }), }); const page = await response.json(); if (!response.ok) throw new Error(`${response.status}: ${page.message}`); for (const item of page.items) { console.log(item); // Process or upsert each result. } cursor = page.next_cursor; } while (cursor); ``` ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [Receive and verify webhooks](/developers/webhooks) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/webhooks.ListWebhookEvents' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "webhook_id": "e_example" }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/webhooks.ListWebhookEvents", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "webhook_id": "e_example" }), }); 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 payload = { "webhook_id": "e_example" } request = Request( "https://api.brigg.app/v1/operations/webhooks.ListWebhookEvents", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "event_id": "e_example", "event": "resource.created", "version": "v1", "occurred_at": "2026-11-10T09:00:00.000Z", "resource": { "id": "e_example", "type": "core:Company", "version": "1" } } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "webhook_id": { "type": "string", "minLength": 1, "description": "Identifier of the approved webhook subscription. After administrator approval, discover it with `webhooks.ListWebhookSubscriptions` using a credential with read access to every selected resource type. It is different from an event ID or delivery ID." }, "cursor": { "type": "string", "description": "Opaque next_cursor returned by this webhook's preceding page. Keep the same webhook and credential; omit it to start a new listing." }, "limit": { "type": "integer", "minimum": 1, "maximum": 100, "default": 50, "description": "Maximum number of results to return in this page. Continue with next_cursor when returned." }, "since": { "type": "integer", "minimum": 0, "description": "Earliest event creation time to return, in Unix milliseconds. Recovery is limited to the 30-day retention window." } }, "required": [ "webhook_id" ], "additionalProperties": false, "examples": [ { "webhook_id": "e_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "event_id": { "type": "string", "description": "Stable event identifier. Deduplicate notifications by this value, including retries and deliberate replays." }, "event": { "type": "string", "enum": [ "resource.created", "resource.updated", "resource.deleted" ], "description": "Event name. Supported values: `meeting.completed`, `resource.created`, `resource.updated`, `resource.deleted`. See the [event reference](/developers/events) for payloads and delivery contracts." }, "version": { "type": "string", "const": "v1", "description": "Payload contract version used to serialize this event." }, "occurred_at": { "type": "string", "format": "date-time", "description": "Event creation time in Unix milliseconds." }, "resource": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier. Use the value returned by a create or list operation." }, "type": { "type": "string", "description": "Type identifying which variant of this model applies." }, "version": { "type": "string", "description": "Opaque resource revision. Events may arrive out of order." } }, "required": [ "id", "type", "version" ], "additionalProperties": false, "description": "Affected record's type and ID; the event does not include the record's complete contents." }, "changed_fields": { "type": "array", "items": { "type": "string" }, "description": "Names of fields changed by an update, when supplied. Fetch the record to read its current values." }, "test": { "type": "boolean", "const": true, "description": "Whether this is a synthetic test event rather than a real resource change." } }, "required": [ "event_id", "event", "version", "occurred_at", "resource" ], "additionalProperties": false, "title": "Webhook event" }, "description": "Recoverable events for the selected webhook, within the 30-day retention window. Pass next_cursor as cursor to continue when a next cursor is returned." }, "next_cursor": { "type": "string", "description": "Continue this webhook's listing with this value as cursor. Omitted on the final page." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "event_id": "e_example", "event": "resource.created", "version": "v1", "occurred_at": "2026-11-10T09:00:00.000Z", "resource": { "id": "e_example", "type": "core:Company", "version": "1" } } ] } ] } ``` --- # List webhooks List webhook subscriptions, supported event names and eligible shared resource types. Signing secrets are excluded. Resource type identifiers can be used when preparing a subscription. POST https://api.brigg.app/v1/operations/webhooks.ListWebhooks ## Access & visibility Allow `webhooks.ListWebhooks` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/permissions) ## Request No parameters. Send an empty JSON object (`{}`). ## Discover what can be subscribed to This administrator view returns three independent collections: `events` is the event-name catalogue, `resources` is the eligible shared resource catalogue, and `items` is the existing subscription list. An empty `items` does not mean there are no supported events. For an integration that only needs its granted subscriptions, use [List webhook subscriptions](/developers/reference/webhooks/ListWebhookSubscriptions). That operation checks the credential's resource grants; this administrator catalogue requires an approved owner/admin identity. Neither response returns signing secrets. Pass exact `resources[].type` values as `resource_types` when [preparing a webhook](/developers/reference/webhooks/PrepareWebhook). An administrator must approve the proposal before it becomes an active subscription. New resource types are not added to an existing subscription automatically. ## Response Returns **200 OK** with a JSON body. This operation has no continuation cursor. An empty `items` array means no matching visible results were returned. | Field | Type | Required | Description | | --- | --- | --- | --- | | `events` | array of string | Yes | Supported event-name strings, not event records or delivery history. See the [event reference](/developers/events) for each payload. | | `resources` | array of [object](#response-resources) | No | Published shared resources available to this credential for webhook subscriptions. | | `items` | array of [Webhook subscription](#webhook-subscription-response-items) | Yes | Workspace webhook subscriptions; supported events and resource types are returned separately. This operation has no cursor pagination. | ### response.resources[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `type` | string | Yes | Exact resource type identifier to put in resource_types, for example core:Company. This is not an operation namespace or a model-variant tag. | | `label` | string | Yes | Human-readable name of the supported resource or event. | | `app` | string | Yes | Internal app identifier owning the resource; use label for display and type for subscription selection. | ### Webhook subscription · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Webhook subscription ID used by DeleteWebhook and TestWebhook. | | `url` | string | Yes | Approved HTTPS destination that receives deliveries. This is not a Brigg API endpoint. | | `event` | string | Yes | Event name. Supported values: `meeting.completed`, `resource.created`, `resource.updated`, `resource.deleted`. See the [event reference](/developers/events) for payloads and delivery contracts. | | `version` | string | No | Payload contract version used for this subscription. | | `resource_types` | array of string | No | Explicit resource type identifiers, such as `core:Company` or a workspace app's qualified type. Discover the exact values from `resource` on the record operations returned by `GET /v1/operations` using a key with access to those records. These are resource types, not app names or operation namespaces. Required and non-empty for `resource.created`, `resource.updated` and `resource.deleted`; omit for legacy `meeting.completed`. Only selected, published shared types are included; new types are never added automatically. See [webhook resource selection](/developers/webhooks#choose-resource-types). | | `enabled` | boolean | Yes | Whether this subscription may receive deliveries. It does not confirm that its endpoint is healthy. | | `consecutive_failures` | number | Yes | Consecutive failed deliveries recorded for this subscription. | | `last_failure_reason` | string or null | Yes | Most recent delivery failure, or null if none is recorded. | | `last_delivered_at` | number or null | Yes | Most recent successful delivery time in Unix milliseconds, or null before a successful delivery. | | `created_at` | number | Yes | Subscription creation time in Unix milliseconds. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [Prepare webhook](/developers/reference/webhooks/PrepareWebhook) - [List webhook subscriptions](/developers/reference/webhooks/ListWebhookSubscriptions) - [List webhook deliveries](/developers/reference/webhooks/ListWebhookDeliveries) - [List webhook events](/developers/reference/webhooks/ListWebhookEvents) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/webhooks.ListWebhooks' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{}' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/webhooks.ListWebhooks", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/webhooks.ListWebhooks", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "events": [ "meeting.completed", "resource.created", "resource.updated", "resource.deleted" ], "items": [ { "id": "webhook_crm", "url": "https://example.com/webhooks/brigg", "event": "resource.updated", "version": "v1", "resource_types": [ "core:Company" ], "enabled": true, "consecutive_failures": 0, "last_failure_reason": null, "last_delivered_at": null, "created_at": 1794301200000 } ], "resources": [ { "type": "core:Company", "label": "Company", "app": "customers" } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": {}, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "events": { "type": "array", "items": { "type": "string" }, "description": "Supported event-name strings, not event records or delivery history. See the [event reference](/developers/events) for each payload." }, "resources": { "type": "array", "items": { "type": "object", "properties": { "type": { "type": "string", "description": "Exact resource type identifier to put in resource_types, for example core:Company. This is not an operation namespace or a model-variant tag." }, "label": { "type": "string", "description": "Human-readable name of the supported resource or event." }, "app": { "type": "string", "description": "Internal app identifier owning the resource; use label for display and type for subscription selection." } }, "required": [ "type", "label", "app" ], "additionalProperties": false }, "description": "Published shared resources available to this credential for webhook subscriptions." }, "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Webhook subscription ID used by DeleteWebhook and TestWebhook.", "examples": [ "webhook_crm" ] }, "url": { "type": "string", "description": "Approved HTTPS destination that receives deliveries. This is not a Brigg API endpoint.", "examples": [ "https://example.com/webhooks/brigg" ] }, "event": { "type": "string", "description": "Event name. Supported values: `meeting.completed`, `resource.created`, `resource.updated`, `resource.deleted`. See the [event reference](/developers/events) for payloads and delivery contracts.", "examples": [ "resource.updated" ] }, "version": { "type": "string", "description": "Payload contract version used for this subscription.", "examples": [ "v1" ] }, "resource_types": { "type": "array", "items": { "type": "string" }, "description": "Explicit resource type identifiers, such as `core:Company` or a workspace app's qualified type. Discover the exact values from `resource` on the record operations returned by `GET /v1/operations` using a key with access to those records. These are resource types, not app names or operation namespaces. Required and non-empty for `resource.created`, `resource.updated` and `resource.deleted`; omit for legacy `meeting.completed`. Only selected, published shared types are included; new types are never added automatically. See [webhook resource selection](/developers/webhooks#choose-resource-types).", "examples": [ [ "core:Company" ] ] }, "enabled": { "type": "boolean", "description": "Whether this subscription may receive deliveries. It does not confirm that its endpoint is healthy.", "examples": [ true ] }, "consecutive_failures": { "type": "number", "description": "Consecutive failed deliveries recorded for this subscription.", "examples": [ 0 ] }, "last_failure_reason": { "type": [ "string", "null" ], "description": "Most recent delivery failure, or null if none is recorded.", "examples": [ null ] }, "last_delivered_at": { "type": [ "number", "null" ], "description": "Most recent successful delivery time in Unix milliseconds, or null before a successful delivery.", "examples": [ null ] }, "created_at": { "type": "number", "description": "Subscription creation time in Unix milliseconds.", "examples": [ 1794301200000 ] } }, "required": [ "id", "url", "event", "enabled", "consecutive_failures", "last_failure_reason", "last_delivered_at", "created_at" ], "additionalProperties": false, "title": "Webhook subscription" }, "description": "Workspace webhook subscriptions; supported events and resource types are returned separately. This operation has no cursor pagination." } }, "required": [ "items", "events" ], "additionalProperties": false, "examples": [ { "events": [ "meeting.completed", "resource.created", "resource.updated", "resource.deleted" ], "items": [ { "id": "webhook_crm", "url": "https://example.com/webhooks/brigg", "event": "resource.updated", "version": "v1", "resource_types": [ "core:Company" ], "enabled": true, "consecutive_failures": 0, "last_failure_reason": null, "last_delivered_at": null, "created_at": 1794301200000 } ], "resources": [ { "type": "core:Company", "label": "Company", "app": "customers" } ] } ] } ``` --- # List webhook subscriptions Find approved subscriptions for the published resource types your credential can read. Use a subscription’s ID to inspect deliveries, recover missed events or request a replay. Destination URLs, secrets and legacy transcript exports are excluded. POST https://api.brigg.app/v1/operations/webhooks.ListWebhookSubscriptions ## Access & visibility Allow `webhooks.ListWebhookSubscriptions` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `event` | string | No | Event name. Supported values: `meeting.completed`, `resource.created`, `resource.updated`, `resource.deleted`. See the [event reference](/developers/events) for payloads and delivery contracts. | ## Response Returns **200 OK** with a JSON body. This operation has no continuation cursor. An empty `items` array means no matching visible results were returned. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [Webhook subscription](#webhook-subscription-response-items) | Yes | Subscriptions accessible under the credential's operation and resource grants, optionally filtered by event. This operation has no cursor pagination. | ### Webhook subscription · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `webhook_id` | string | Yes | Identifier of the approved webhook subscription. After administrator approval, discover it with `webhooks.ListWebhookSubscriptions` using a credential with read access to every selected resource type. It is different from an event ID or delivery ID. | | `event` | string | Yes | Event name. Supported values: `meeting.completed`, `resource.created`, `resource.updated`, `resource.deleted`. See the [event reference](/developers/events) for payloads and delivery contracts. | | `resource_types` | array of string | Yes | Explicit resource type identifiers, such as `core:Company` or a workspace app's qualified type. Discover the exact values from `resource` on the record operations returned by `GET /v1/operations` using a key with access to those records. These are resource types, not app names or operation namespaces. Required and non-empty for `resource.created`, `resource.updated` and `resource.deleted`; omit for legacy `meeting.completed`. Only selected, published shared types are included; new types are never added automatically. See [webhook resource selection](/developers/webhooks#choose-resource-types). | | `enabled` | boolean | Yes | Whether this subscription may receive deliveries. It does not confirm that its endpoint is healthy. | | `created_at` | number | Yes | Creation time in Unix milliseconds. | | `last_delivered_at` | number or null | Yes | Most recent successful delivery time in Unix milliseconds, or null before a successful delivery. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [Receive and verify webhooks](/developers/webhooks) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/webhooks.ListWebhookSubscriptions' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{}' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/webhooks.ListWebhookSubscriptions", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/webhooks.ListWebhookSubscriptions", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "webhook_id": "webhook_crm", "event": "resource.updated", "resource_types": [ "core:Company" ], "enabled": true, "created_at": 1794301200000, "last_delivered_at": null } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "event": { "type": "string", "description": "Event name. Supported values: `meeting.completed`, `resource.created`, `resource.updated`, `resource.deleted`. See the [event reference](/developers/events) for payloads and delivery contracts." } }, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "webhook_id": { "type": "string", "description": "Identifier of the approved webhook subscription. After administrator approval, discover it with `webhooks.ListWebhookSubscriptions` using a credential with read access to every selected resource type. It is different from an event ID or delivery ID.", "examples": [ "webhook_crm" ] }, "event": { "type": "string", "description": "Event name. Supported values: `meeting.completed`, `resource.created`, `resource.updated`, `resource.deleted`. See the [event reference](/developers/events) for payloads and delivery contracts.", "examples": [ "resource.updated" ] }, "resource_types": { "type": "array", "items": { "type": "string" }, "description": "Explicit resource type identifiers, such as `core:Company` or a workspace app's qualified type. Discover the exact values from `resource` on the record operations returned by `GET /v1/operations` using a key with access to those records. These are resource types, not app names or operation namespaces. Required and non-empty for `resource.created`, `resource.updated` and `resource.deleted`; omit for legacy `meeting.completed`. Only selected, published shared types are included; new types are never added automatically. See [webhook resource selection](/developers/webhooks#choose-resource-types).", "examples": [ [ "core:Company" ] ] }, "enabled": { "type": "boolean", "description": "Whether this subscription may receive deliveries. It does not confirm that its endpoint is healthy.", "examples": [ true ] }, "created_at": { "type": "number", "description": "Creation time in Unix milliseconds." }, "last_delivered_at": { "type": [ "number", "null" ], "description": "Most recent successful delivery time in Unix milliseconds, or null before a successful delivery.", "examples": [ null ] } }, "required": [ "webhook_id", "event", "resource_types", "enabled", "created_at", "last_delivered_at" ], "additionalProperties": false, "title": "Webhook subscription" }, "description": "Subscriptions accessible under the credential's operation and resource grants, optionally filtered by event. This operation has no cursor pagination." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "webhook_id": "webhook_crm", "event": "resource.updated", "resource_types": [ "core:Company" ], "enabled": true, "created_at": 1794301200000, "last_delivered_at": null } ] } ] } ``` --- # Prepare webhook Prepare a webhook subscription for an administrator to review. Returns its configuration and approval URL. No subscription is activated until a person approves it. POST https://api.brigg.app/v1/operations/webhooks.PrepareWebhook ## Access & visibility Allow `webhooks.PrepareWebhook` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `url` | string | Yes | An HTTPS endpoint on a public host. At least 1 character. At most 2048 characters. | | `event` | string | Yes | Event name. Supported values: `meeting.completed`, `resource.created`, `resource.updated`, `resource.deleted`. See the [event reference](/developers/events) for payloads and delivery contracts. At least 1 character. At most 64 characters. | | `resource_types` | array of string | No | Explicit resource type identifiers, such as `core:Company` or a workspace app's qualified type. Discover the exact values from `resource` on the record operations returned by `GET /v1/operations` using a key with access to those records. These are resource types, not app names or operation namespaces. Required and non-empty for `resource.created`, `resource.updated` and `resource.deleted`; omit for legacy `meeting.completed`. Only selected, published shared types are included; new types are never added automatically. See [webhook resource selection](/developers/webhooks#choose-resource-types). | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `configuration` | [object](#response-configuration) | Yes | Proposed webhook settings for a person to approve in Brigg; this is not an active subscription. | | `approval_url` | string | Yes | Path in the Brigg application where an administrator reviews this exact proposal. Open it on your Brigg application origin. Preparing a proposal does not create a subscription. | | `message` | string | Yes | Instructions or outcome for the webhook action. | ### response.configuration | Field | Type | Required | Description | | --- | --- | --- | --- | | `url` | string | Yes | Absolute URL, including its scheme. | | `event` | string | Yes | Event name. Supported values: `meeting.completed`, `resource.created`, `resource.updated`, `resource.deleted`. See the [event reference](/developers/events) for payloads and delivery contracts. | | `resource_types` | array of string | Yes | Explicit resource type identifiers, such as `core:Company` or a workspace app's qualified type. Discover the exact values from `resource` on the record operations returned by `GET /v1/operations` using a key with access to those records. These are resource types, not app names or operation namespaces. Required and non-empty for `resource.created`, `resource.updated` and `resource.deleted`; omit for legacy `meeting.completed`. Only selected, published shared types are included; new types are never added automatically. See [webhook resource selection](/developers/webhooks#choose-resource-types). | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [Receive and verify webhooks](/developers/webhooks) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/webhooks.PrepareWebhook' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{ "url": "https://example.com/webhooks/brigg", "event": "resource.updated", "resource_types": [ "core:Company" ] }' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/webhooks.PrepareWebhook", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://example.com/webhooks/brigg", "event": "resource.updated", "resource_types": [ "core:Company" ] }), }); 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 payload = { "url": "https://example.com/webhooks/brigg", "event": "resource.updated", "resource_types": [ "core:Company" ] } request = Request( "https://api.brigg.app/v1/operations/webhooks.PrepareWebhook", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "configuration": { "url": "https://example.com/webhooks/brigg", "event": "resource.updated", "resource_types": [ "core:Company" ] }, "approval_url": "/settings/webhooks?webhook_proposal=%7B%22url%22%3A%22https%3A%2F%2Fexample.com%2Fwebhooks%2Fbrigg%22%2C%22event%22%3A%22resource.updated%22%2C%22resource_types%22%3A%5B%22core%3ACompany%22%5D%7D", "message": "Review the endpoint and resource access in Brigg Settings." } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "url": { "type": "string", "minLength": 1, "maxLength": 2048, "description": "An HTTPS endpoint on a public host." }, "event": { "type": "string", "minLength": 1, "maxLength": 64, "description": "Event name. Supported values: `meeting.completed`, `resource.created`, `resource.updated`, `resource.deleted`. See the [event reference](/developers/events) for payloads and delivery contracts." }, "resource_types": { "type": "array", "items": { "type": "string", "minLength": 1 }, "description": "Explicit resource type identifiers, such as `core:Company` or a workspace app's qualified type. Discover the exact values from `resource` on the record operations returned by `GET /v1/operations` using a key with access to those records. These are resource types, not app names or operation namespaces. Required and non-empty for `resource.created`, `resource.updated` and `resource.deleted`; omit for legacy `meeting.completed`. Only selected, published shared types are included; new types are never added automatically. See [webhook resource selection](/developers/webhooks#choose-resource-types)." } }, "required": [ "url", "event" ], "additionalProperties": false, "examples": [ { "url": "https://example.com/webhooks/brigg", "event": "resource.updated", "resource_types": [ "core:Company" ] } ] } ``` ```json-schema-response { "type": "object", "properties": { "configuration": { "type": "object", "properties": { "url": { "type": "string", "description": "Absolute URL, including its scheme." }, "event": { "type": "string", "description": "Event name. Supported values: `meeting.completed`, `resource.created`, `resource.updated`, `resource.deleted`. See the [event reference](/developers/events) for payloads and delivery contracts." }, "resource_types": { "type": "array", "items": { "type": "string" }, "description": "Explicit resource type identifiers, such as `core:Company` or a workspace app's qualified type. Discover the exact values from `resource` on the record operations returned by `GET /v1/operations` using a key with access to those records. These are resource types, not app names or operation namespaces. Required and non-empty for `resource.created`, `resource.updated` and `resource.deleted`; omit for legacy `meeting.completed`. Only selected, published shared types are included; new types are never added automatically. See [webhook resource selection](/developers/webhooks#choose-resource-types)." } }, "required": [ "url", "event", "resource_types" ], "additionalProperties": false, "description": "Proposed webhook settings for a person to approve in Brigg; this is not an active subscription." }, "approval_url": { "type": "string", "description": "Path in the Brigg application where an administrator reviews this exact proposal. Open it on your Brigg application origin. Preparing a proposal does not create a subscription." }, "message": { "type": "string", "description": "Instructions or outcome for the webhook action." } }, "required": [ "configuration", "approval_url", "message" ], "additionalProperties": false, "examples": [ { "configuration": { "url": "https://example.com/webhooks/brigg", "event": "resource.updated", "resource_types": [ "core:Company" ] }, "approval_url": "/settings/webhooks?webhook_proposal=%7B%22url%22%3A%22https%3A%2F%2Fexample.com%2Fwebhooks%2Fbrigg%22%2C%22event%22%3A%22resource.updated%22%2C%22resource_types%22%3A%5B%22core%3ACompany%22%5D%7D", "message": "Review the endpoint and resource access in Brigg Settings." } ] } ``` --- # Delete webhook Delete a webhook subscription and stop further deliveries to its endpoint. POST https://api.brigg.app/v1/operations/webhooks.DeleteWebhook ## Access & visibility Allow `webhooks.DeleteWebhook` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | Use the subscription id returned by ListWebhooks. It is not an event ID, delivery ID or signing secret. [webhooks.ListWebhooks](/developers/reference/webhooks/ListWebhooks). At least 1 character. | ## Stop a subscription Find the subscription in [List webhooks](/developers/reference/webhooks/ListWebhooks) and send its id. This removes the subscription; it does not undo changes already delivered to your endpoint. Pending delivery work checks whether the subscription still exists and skips deleted subscriptions. A request already in flight can still reach your endpoint. Deletion has no public undo operation. If you need the stream again, prepare a new subscription and obtain administrator approval. A fresh delete of an absent subscription returns 404 not_found; retrying a successful original request with the same idempotency key replays its original result. The deleted subscription is no longer available for event recovery or replay. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [List webhooks](/developers/reference/webhooks/ListWebhooks) - [Prepare webhook](/developers/reference/webhooks/PrepareWebhook) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Stop a subscription Copy id from the subscription catalogue, not an event or delivery. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/webhooks.DeleteWebhook' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "wh_company_changes" }' ``` #### TypeScript ```typescript 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/webhooks.DeleteWebhook", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "wh_company_changes" }), }); 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": "wh_company_changes" } request = Request( "https://api.brigg.app/v1/operations/webhooks.DeleteWebhook", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Use the subscription id returned by ListWebhooks. It is not an event ID, delivery ID or signing secret. [webhooks.ListWebhooks](/developers/reference/webhooks/ListWebhooks)." } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "wh_company_changes" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." } }, "required": [ "ok" ], "additionalProperties": false, "examples": [ { "ok": true } ] } ``` --- # Test webhook Send a marked sample event to a webhook and report the endpoint's response. Test deliveries are not retried and do not change the subscription's failure count. POST https://api.brigg.app/v1/operations/webhooks.TestWebhook ## Access & visibility Allow `webhooks.TestWebhook` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | Use the subscription id returned by ListWebhooks. This sends a synthetic event to its approved endpoint. [webhooks.ListWebhooks](/developers/reference/webhooks/ListWebhooks). At least 1 character. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `success` | boolean | Yes | Whether the test delivery reached the endpoint successfully. | | `status` | number | No | Current state reported for this item. Treat values as extensible unless an enum is declared. | | `error` | string | No | Failure reported for this test delivery. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps - [Receive and verify webhooks](/developers/webhooks) - [List webhooks](/developers/reference/webhooks/ListWebhooks) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/webhooks.TestWebhook' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "id": "e_example" }' ``` #### TypeScript ```typescript 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/webhooks.TestWebhook", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "id": "e_example" }), }); 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_example" } request = Request( "https://api.brigg.app/v1/operations/webhooks.TestWebhook", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "success": false } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Use the subscription id returned by ListWebhooks. This sends a synthetic event to its approved endpoint. [webhooks.ListWebhooks](/developers/reference/webhooks/ListWebhooks)." } }, "required": [ "id" ], "additionalProperties": false, "examples": [ { "id": "e_example" } ] } ``` ```json-schema-response { "type": "object", "properties": { "success": { "type": "boolean", "description": "Whether the test delivery reached the endpoint successfully." }, "status": { "type": "number", "description": "Current state reported for this item. Treat values as extensible unless an enum is declared." }, "error": { "type": "string", "description": "Failure reported for this test delivery." } }, "required": [ "success" ], "additionalProperties": false, "examples": [ { "success": false } ] } ``` --- # Get agent network Read the workspace's policy for external network access, its allowed domains and whether the caller can change it. POST https://api.brigg.app/v1/operations/workspace.GetAgentNetwork ## Access & visibility Allow `workspace.GetAgentNetwork` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/permissions) ## Request No parameters. Send an empty JSON object (`{}`). ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `policy` | string | Yes | Workspace policy governing external network access. | | `allowed_domains` | array of string | Yes | Custom domains. | | `updated_at` | number or null | Yes | Set at. | | `workspace_domain` | string or null | Yes | Org domain. | | `service_domains` | array of string | Yes | Brigg domains. | | `can_manage` | boolean | Yes | Whether the acting member can change this configuration. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/workspace.GetAgentNetwork' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{}' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/workspace.GetAgentNetwork", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/workspace.GetAgentNetwork", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "policy": "unrestricted", "allowed_domains": [], "updated_at": null, "workspace_domain": "example.com", "service_domains": [], "can_manage": false } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": {}, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "policy": { "type": "string", "description": "Workspace policy governing external network access." }, "allowed_domains": { "type": "array", "items": { "type": "string" }, "description": "Custom domains." }, "updated_at": { "type": [ "number", "null" ], "description": "Set at." }, "workspace_domain": { "type": [ "string", "null" ], "description": "Org domain." }, "service_domains": { "type": "array", "items": { "type": "string" }, "description": "Brigg domains." }, "can_manage": { "type": "boolean", "description": "Whether the acting member can change this configuration." } }, "required": [ "policy", "allowed_domains", "updated_at", "workspace_domain", "service_domains", "can_manage" ], "additionalProperties": false, "examples": [ { "policy": "unrestricted", "allowed_domains": [], "updated_at": null, "workspace_domain": "example.com", "service_domains": [], "can_manage": false } ] } ``` --- # List apps List released apps the caller can open, with their names, IDs and default view metadata. Private apps belonging to other people and unpublished drafts are excluded. POST https://api.brigg.app/v1/operations/workspace.ListApps ## Access & visibility Allow `workspace.ListApps` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/permissions) ## Request No parameters. Send an empty JSON object (`{}`). ## Response Returns **200 OK** with a JSON body. This operation has no continuation cursor. An empty `items` array means no matching visible results were returned. This is the acting member's app-menu catalogue. It excludes surface-owned content such as newsletters and signing documents; use ListBundles for the wider content catalogue. It reports a default view, not every view or an app's API contract. To call a workspace app, discover its published operations through GET /v1/operations using your credential, or GET /v1/openapi.json for its schema. An app can be visible here without publishing API operations. Never construct an operation name from its label or bundle_id. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [Installed app](#installed-app-response-items) | Yes | Installed apps visible to the acting member. This operation has no cursor pagination. | ### Installed app · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `bundle_id` | string | Yes | Installed app ID. This is not its public operation namespace. | | `kind` | string | Yes | Content kind such as app, template or document. Use ListBundles when you need surface-owned content rather than menu entries. | | `label` | string | Yes | Human-readable app name; do not treat it as an identifier. | | `default_view` | null or string | Yes | Initial view chosen when opening the app, or null when no view was selected. | | `activated_at` | number | Yes | Time the app was installed, in Unix milliseconds. | | `icon_slug` | null or string | Yes | Icon name used to display the app, or null when none is configured. | | `render_mode` | string | Yes | Presentation hint such as runtime, static or email. It is not an authorization level or a public operation namespace. | | `category` | string | Yes | Product category used to organize the app in Brigg. | | `has_static_routes` | boolean | Yes | Whether the app defines static website routes; this alone does not make its content publicly accessible. Allowed: `false`, `true`. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [List bundles](/developers/reference/workspace/ListBundles) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/workspace.ListApps' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{}' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/workspace.ListApps", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/workspace.ListApps", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "bundle_id": "core", "kind": "app", "label": "Customers", "default_view": null, "activated_at": 1794301200000, "icon_slug": null, "render_mode": "runtime", "category": "crm", "has_static_routes": false } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": {}, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "title": "Installed app", "type": "object", "properties": { "bundle_id": { "type": "string", "description": "Installed app ID. This is not its public operation namespace.", "examples": [ "core" ] }, "kind": { "type": "string", "description": "Content kind such as app, template or document. Use ListBundles when you need surface-owned content rather than menu entries.", "examples": [ "app" ] }, "label": { "type": "string", "description": "Human-readable app name; do not treat it as an identifier.", "examples": [ "Customers" ] }, "default_view": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Initial view chosen when opening the app, or null when no view was selected.", "examples": [ null ] }, "activated_at": { "type": "number", "description": "Time the app was installed, in Unix milliseconds.", "examples": [ 1794301200000 ] }, "icon_slug": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Icon name used to display the app, or null when none is configured.", "examples": [ null ] }, "render_mode": { "type": "string", "description": "Presentation hint such as runtime, static or email. It is not an authorization level or a public operation namespace.", "examples": [ "runtime" ] }, "category": { "type": "string", "description": "Product category used to organize the app in Brigg.", "examples": [ "crm" ] }, "has_static_routes": { "type": "boolean", "enum": [ false, true ], "description": "Whether the app defines static website routes; this alone does not make its content publicly accessible.", "examples": [ false ] } }, "required": [ "bundle_id", "kind", "label", "default_view", "activated_at", "icon_slug", "render_mode", "category", "has_static_routes" ], "additionalProperties": false }, "description": "Installed apps visible to the acting member. This operation has no cursor pagination." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "bundle_id": "core", "kind": "app", "label": "Customers", "default_view": null, "activated_at": 1794301200000, "icon_slug": null, "render_mode": "runtime", "category": "crm", "has_static_routes": false } ] } ] } ``` --- # List bundles List the apps, websites, newsletters, documents and templates you can access. Each item identifies its business content type. Use its content ID with content management operations or as the corresponding document or template ID. POST https://api.brigg.app/v1/operations/workspace.ListBundles ## Access & visibility Allow `workspace.ListBundles` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/permissions) ## Request No parameters. Send an empty JSON object (`{}`). ## Response Returns **200 OK** with a JSON body. This operation has no continuation cursor. An empty `items` array means no matching visible results were returned. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [Workspace content](#workspace-content-response-items) | Yes | Apps, websites, documents, templates, newsletters and integrations visible to the acting member; kind identifies the content type. This operation has no cursor pagination. | ### Workspace content · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `content_id` | string | Yes | Content ID used by document, app and sharing operations. It is distinct from an uploaded file ID. | | `label` | string | Yes | Human-readable name of the content item. | | `kind` | string | Yes | Content category; use it to choose the matching document, template, website or app workflow. Allowed: `"app"`, `"website"`, `"newsletter"`, `"document"`, `"template"`, `"integration"`. | | `published` | boolean | Yes | Whether a published version exists. Publication here does not by itself mean anonymous public access. | | `has_unsaved_changes` | boolean | Yes | Whether the acting member has changes that differ from the saved version. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/workspace.ListBundles' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{}' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/workspace.ListBundles", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/workspace.ListBundles", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "content_id": "document_proposal", "label": "Consulting proposal", "kind": "document", "published": true, "has_unsaved_changes": false } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": {}, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "content_id": { "type": "string", "description": "Content ID used by document, app and sharing operations. It is distinct from an uploaded file ID.", "examples": [ "document_proposal" ] }, "label": { "type": "string", "description": "Human-readable name of the content item.", "examples": [ "Consulting proposal" ] }, "kind": { "type": "string", "enum": [ "app", "website", "newsletter", "document", "template", "integration" ], "description": "Content category; use it to choose the matching document, template, website or app workflow.", "examples": [ "document" ] }, "published": { "type": "boolean", "description": "Whether a published version exists. Publication here does not by itself mean anonymous public access.", "examples": [ true ] }, "has_unsaved_changes": { "type": "boolean", "description": "Whether the acting member has changes that differ from the saved version.", "examples": [ false ] } }, "required": [ "content_id", "label", "kind", "published", "has_unsaved_changes" ], "additionalProperties": false, "title": "Workspace content" }, "description": "Apps, websites, documents, templates, newsletters and integrations visible to the acting member; kind identifies the content type. This operation has no cursor pagination." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "content_id": "document_proposal", "label": "Consulting proposal", "kind": "document", "published": true, "has_unsaved_changes": false } ] } ] } ``` --- # List templates List shared templates and the caller's own templates. A null owner_account_id identifies a shared template. POST https://api.brigg.app/v1/operations/workspace.ListTemplates ## Access & visibility Allow `workspace.ListTemplates` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/permissions) ## Request No parameters. Send an empty JSON object (`{}`). ## Response Returns **200 OK** with a JSON body. This operation has no continuation cursor. An empty `items` array means no matching visible results were returned. Use template_id as the template identity. owner_account_id is null for a shared template and names the owner for a personal template. category and signable do not prove that a template contains an original Word file; Word filling requires a template prepared from a .docx in Brigg. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [Document template](#document-template-response-items) | Yes | Document templates available to the acting member. This operation has no cursor pagination. | ### Document template · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `template_id` | string | Yes | Template identifier. | | `label` | string | Yes | Human-readable template name. | | `catalog_id` | null or string | Yes | Source template's catalog identifier, or null for a template without a catalog source. | | `installed_at` | number | Yes | Time the template was installed, in Unix milliseconds. | | `owner_account_id` | null or string | Yes | Owner of a private template, or null for a workspace template. | | `category` | string | Yes | Product category used to organize this template in Brigg. | | `signable` | boolean | Yes | Whether documents made from this template support the signing workflow. Allowed: `false`, `true`. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [List document template fields](/developers/reference/documents/ListDocumentTemplateFields) - [Fill Word template](/developers/reference/documents/FillWordTemplate) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/workspace.ListTemplates' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{}' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/workspace.ListTemplates", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/workspace.ListTemplates", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "template_id": "template_consulting", "label": "Consulting agreement", "catalog_id": null, "installed_at": 1794301200000, "owner_account_id": null, "category": "documents", "signable": true } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": {}, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "title": "Document template", "type": "object", "properties": { "template_id": { "type": "string", "description": "Template identifier.", "examples": [ "template_consulting" ] }, "label": { "type": "string", "description": "Human-readable template name.", "examples": [ "Consulting agreement" ] }, "catalog_id": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Source template's catalog identifier, or null for a template without a catalog source.", "examples": [ null ] }, "installed_at": { "type": "number", "description": "Time the template was installed, in Unix milliseconds.", "examples": [ 1794301200000 ] }, "owner_account_id": { "anyOf": [ { "type": "null" }, { "type": "string" } ], "description": "Owner of a private template, or null for a workspace template.", "examples": [ null ] }, "category": { "type": "string", "description": "Product category used to organize this template in Brigg.", "examples": [ "documents" ] }, "signable": { "type": "boolean", "enum": [ false, true ], "description": "Whether documents made from this template support the signing workflow.", "examples": [ true ] } }, "required": [ "template_id", "label", "catalog_id", "installed_at", "owner_account_id", "category", "signable" ], "additionalProperties": false }, "description": "Document templates available to the acting member. This operation has no cursor pagination." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "template_id": "template_consulting", "label": "Consulting agreement", "catalog_id": null, "installed_at": 1794301200000, "owner_account_id": null, "category": "documents", "signable": true } ] } ] } ``` --- # Get branding Read the workspace's display name, registered name, primary domain, logo, icon and company profile. POST https://api.brigg.app/v1/operations/workspace.GetBranding ## Access & visibility Allow `workspace.GetBranding` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/permissions) ## Request No parameters. Send an empty JSON object (`{}`). ## Response Returns **200 OK** with a JSON body. These are the workspace's branding assets and profile, not a customer's Company record. Asset URLs are public presentation assets; do not upload confidential images as branding. | Field | Type | Required | Description | | --- | --- | --- | --- | | `name` | string | Yes | Display name. | | `registered_name` | string | Yes | Registered legal name of the organization. | | `domain` | string or null | Yes | Website hostname, without a scheme or path. | | `icon_url` | string or null | Yes | URL of the workspace's configured icon. | | `logo_url` | string or null | Yes | URL of the workspace's configured logo. | | `profile_md` | string or null | Yes | Workspace company profile formatted as Markdown. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [Update branding](/developers/reference/workspace/UpdateBranding) - [Refetch brand icon](/developers/reference/workspace/RefetchBrandIcon) - [Generate company profile](/developers/reference/workspace/GenerateCompanyProfile) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/workspace.GetBranding' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{}' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/workspace.GetBranding", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/workspace.GetBranding", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "name": "Example project", "registered_name": "Northstar Consulting AS", "domain": null, "icon_url": "https://example.com/icon.png", "logo_url": "https://example.com/logo.svg", "profile_md": "Northstar helps small businesses organize their customer work." } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": {}, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "name": { "type": "string", "description": "Display name." }, "registered_name": { "type": "string", "description": "Registered legal name of the organization." }, "domain": { "type": [ "string", "null" ], "description": "Website hostname, without a scheme or path." }, "icon_url": { "type": [ "string", "null" ], "description": "URL of the workspace's configured icon." }, "logo_url": { "type": [ "string", "null" ], "description": "URL of the workspace's configured logo." }, "profile_md": { "type": [ "string", "null" ], "description": "Workspace company profile formatted as Markdown." } }, "required": [ "name", "registered_name", "domain", "icon_url", "logo_url", "profile_md" ], "additionalProperties": false, "examples": [ { "name": "Example project", "registered_name": "Northstar Consulting AS", "domain": null, "icon_url": "https://example.com/icon.png", "logo_url": "https://example.com/logo.svg", "profile_md": "Northstar helps small businesses organize their customer work." } ] } ``` --- # Refetch brand icon Refresh the workspace's icon from its primary website. Reports an error when the domain or a suitable icon is unavailable. POST https://api.brigg.app/v1/operations/workspace.RefetchBrandIcon ## Access & visibility Allow `workspace.RefetchBrandIcon` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/permissions) ## Request No parameters. Send an empty JSON object (`{}`). ## Refresh from the workspace website Read [Get branding](/developers/reference/workspace/GetBranding) first. This uses the workspace's primary domain configured in Brigg; it does not accept an arbitrary URL. It fetches that website's icon and replaces the workspace icon only. It does not update the logo or company profile. If there is no configured domain, correct the workspace profile in Brigg. If the website cannot be read or supplies no usable icon, fix the website or use [Update branding](/developers/reference/workspace/UpdateBranding) with an explicit image. Re-read branding after success when updating a local cache. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `icon_url` | null or string | Yes | Absolute URL of the refreshed workspace icon. Null means the saved image could not be represented as a public URL; it is not an instruction to erase a cached icon. Read GetBranding to reconcile the saved branding. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 400 | `no_domain` | Set the workspace's primary website in Brigg before refreshing its icon. | | 502 | `scrape_failed` | The website could not be read. Check that it is reachable, or upload an icon through UpdateBranding. | | 404 | `icon_not_found` | No usable website icon was found. Supply an image through UpdateBranding instead. | ## Next steps - [Get branding](/developers/reference/workspace/GetBranding) - [Update branding](/developers/reference/workspace/UpdateBranding) - [Update workspace profile](/developers/reference/workspace/UpdateWorkspaceProfile) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/workspace.RefetchBrandIcon' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{}' ``` #### TypeScript ```typescript 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/workspace.RefetchBrandIcon", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({}), }); 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 = {} request = Request( "https://api.brigg.app/v1/operations/workspace.RefetchBrandIcon", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "icon_url": "https://example.com/icon.png" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": {}, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "icon_url": { "description": "Absolute URL of the refreshed workspace icon. Null means the saved image could not be represented as a public URL; it is not an instruction to erase a cached icon. Read GetBranding to reconcile the saved branding.", "title": "OpenAdThreadSubtaskAgent_phase", "anyOf": [ { "type": "null", "description": "Absolute URL of the refreshed workspace icon. Null means the saved image could not be represented as a public URL; it is not an instruction to erase a cached icon. Read GetBranding to reconcile the saved branding." }, { "type": "string", "description": "Absolute URL of the refreshed workspace icon. Null means the saved image could not be represented as a public URL; it is not an instruction to erase a cached icon. Read GetBranding to reconcile the saved branding." } ] } }, "required": [ "icon_url" ], "additionalProperties": false, "examples": [ { "icon_url": "https://example.com/icon.png" } ] } ``` --- # Update branding Update the workspace's company profile, logo or icon. Image inputs use data URLs; the response contains the resulting image URLs. POST https://api.brigg.app/v1/operations/workspace.UpdateBranding ## Access & visibility Allow `workspace.UpdateBranding` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `profile_md` | string or null | No | Workspace company profile in Markdown. Omit to keep the current profile; null or an empty string clears it. | | `logo_url` | string or null | No | Image data URL to replace the public workspace logo. Omit to keep it; null clears it. This is an image upload, not a private-file attachment. | | `icon_url` | string or null | No | Image data URL to replace the public workspace icon. Omit to keep it; null clears it. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | | `logo_url` | null or string | No | Absolute URL of the saved public logo, or null when cleared. Omitted when the logo was not changed. | | `icon_url` | null or string | No | Absolute URL of the saved public icon, or null when cleared. Omitted when the icon was not changed. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 502 | `logo_store_failed` | The supplied logo could not be stored; check its image data URL. | | 502 | `icon_store_failed` | The supplied icon could not be stored; check its image data URL. | ## Next steps - [Get branding](/developers/reference/workspace/GetBranding) - [Refetch brand icon](/developers/reference/workspace/RefetchBrandIcon) - [Generate company profile](/developers/reference/workspace/GenerateCompanyProfile) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/workspace.UpdateBranding' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{}' ``` #### TypeScript ```typescript 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/workspace.UpdateBranding", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({}), }); 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 = {} request = Request( "https://api.brigg.app/v1/operations/workspace.UpdateBranding", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "profile_md": { "anyOf": [ { "type": "string", "maxLength": 40000, "description": "Workspace company profile in Markdown. Omit to keep the current profile; null or an empty string clears it." }, { "type": "null", "description": "Workspace company profile in Markdown. Omit to keep the current profile; null or an empty string clears it." } ], "description": "Workspace company profile in Markdown. Omit to keep the current profile; null or an empty string clears it." }, "logo_url": { "anyOf": [ { "type": "string", "maxLength": 2000000, "description": "Image data URL to replace the public workspace logo. Omit to keep it; null clears it. This is an image upload, not a private-file attachment." }, { "type": "null", "description": "Image data URL to replace the public workspace logo. Omit to keep it; null clears it. This is an image upload, not a private-file attachment." } ], "description": "Image data URL to replace the public workspace logo. Omit to keep it; null clears it. This is an image upload, not a private-file attachment." }, "icon_url": { "anyOf": [ { "type": "string", "maxLength": 2000000, "description": "Image data URL to replace the public workspace icon. Omit to keep it; null clears it." }, { "type": "null", "description": "Image data URL to replace the public workspace icon. Omit to keep it; null clears it." } ], "description": "Image data URL to replace the public workspace icon. Omit to keep it; null clears it." } }, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." }, "logo_url": { "description": "Absolute URL of the saved public logo, or null when cleared. Omitted when the logo was not changed.", "title": "OpenAdThreadSubtaskAgent_phase", "anyOf": [ { "type": "null", "description": "Absolute URL of the saved public logo, or null when cleared. Omitted when the logo was not changed." }, { "type": "string", "description": "Absolute URL of the saved public logo, or null when cleared. Omitted when the logo was not changed." } ] }, "icon_url": { "description": "Absolute URL of the saved public icon, or null when cleared. Omitted when the icon was not changed.", "title": "OpenAdThreadSubtaskAgent_phase", "anyOf": [ { "type": "null", "description": "Absolute URL of the saved public icon, or null when cleared. Omitted when the icon was not changed." }, { "type": "string", "description": "Absolute URL of the saved public icon, or null when cleared. Omitted when the icon was not changed." } ] } }, "required": [ "ok" ], "additionalProperties": false, "examples": [ { "ok": true } ] } ``` --- # List domain claims List email domains claimed by the workspace, other eligible domains and the workspace's automatic-join setting. POST https://api.brigg.app/v1/operations/workspace.ListDomainClaims ## Access & visibility Allow `workspace.ListDomainClaims` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/permissions) ## Request No parameters. Send an empty JSON object (`{}`). ## Response Returns **200 OK** with a JSON body. This operation has no continuation cursor. An empty `items` array means no matching visible results were returned. This is a read-only view of signup routing. Claiming or releasing a domain and changing automatic joining require a person in Brigg Settings; they are not public API operations. A claim is separate from buying a domain or configuring website DNS. | Field | Type | Required | Description | | --- | --- | --- | --- | | `available` | array of string | Yes | Email domains belonging to verified members that this workspace can currently claim. Already claimed domains and domains held by another workspace are excluded. These are email-domain strings, not network policies or domain-registration offers. | | `auto_join` | boolean | Yes | Whether eligible signups from a claimed email domain can automatically join this workspace. A claim and automatic-join consent are separate settings. | | `items` | array of [Domain claim](#domain-claim-response-items) | Yes | Email-domain claims associated with the workspace. This operation has no cursor pagination. | ### Domain claim · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `domain` | string | Yes | Email domain claimed by this workspace for member joining. | | `source` | string | Yes | How the claim was established: primary for the workspace's primary domain, verified_member for a verified-member claim, or admin for an explicit administrator claim. | | `created_at` | number | Yes | Time the claim was created, in Unix milliseconds. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Claimed and eligible email domains Only items are already claimed. available lists candidates for an administrator to review in Brigg. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/workspace.ListDomainClaims' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{}' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/workspace.ListDomainClaims", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/workspace.ListDomainClaims", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "available": [ "northstar.example" ], "auto_join": false, "items": [ { "domain": "example.com", "source": "primary", "created_at": 1794301200000 } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": {}, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "description": "What the org holds (`claimed`), what it could still take (`available`) and whether auto-join is on. The primary/branding domain is the profile's, not part of this view.", "properties": { "available": { "type": "array", "items": { "type": "string" }, "description": "Email domains belonging to verified members that this workspace can currently claim. Already claimed domains and domains held by another workspace are excluded. These are email-domain strings, not network policies or domain-registration offers." }, "auto_join": { "type": "boolean", "description": "Whether eligible signups from a claimed email domain can automatically join this workspace. A claim and automatic-join consent are separate settings." }, "items": { "type": "array", "items": { "type": "object", "properties": { "domain": { "type": "string", "description": "Email domain claimed by this workspace for member joining.", "examples": [ "example.com" ] }, "source": { "type": "string", "description": "How the claim was established: primary for the workspace's primary domain, verified_member for a verified-member claim, or admin for an explicit administrator claim.", "examples": [ "primary" ] }, "created_at": { "type": "number", "description": "Time the claim was created, in Unix milliseconds.", "examples": [ 1794301200000 ] } }, "required": [ "domain", "source", "created_at" ], "additionalProperties": false, "title": "Domain claim" }, "description": "Email-domain claims associated with the workspace. This operation has no cursor pagination." } }, "required": [ "items", "available", "auto_join" ], "additionalProperties": false, "examples": [ { "available": [ "northstar.example" ], "auto_join": false, "items": [ { "domain": "example.com", "source": "primary", "created_at": 1794301200000 } ] } ] } ``` --- # Get email deliverability Read the workspace's email sending capacity, recent delivery outcomes, sending restrictions and recommended next action. POST https://api.brigg.app/v1/operations/workspace.GetEmailDeliverability ## Access & visibility Allow `workspace.GetEmailDeliverability` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/permissions) ## Request No parameters. Send an empty JSON object (`{}`). ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `tier` | string | Yes | The trust tier. Allowed: `"trial"`, `"free"`, `"paid"`. | | `quota` | [GetEmailDeliverabilityQuota](#getemaildeliverabilityquota-response-quota) | Yes | Current email sending allowance. | | `state` | string | Yes | The send state. Allowed: `"healthy"`, `"approaching"`, `"at_limit"`, `"paused"`. | | `paused` | boolean | Yes | Whether sending is currently paused. | | `paused_reason` | string or null | Yes | Reason sending is paused, when one is recorded. | | `killed` | boolean | Yes | Whether sending has been disabled by a protection rule. | | `window` | [GetEmailDeliverabilityWindow](#getemaildeliverabilitywindow-response-window) | Yes | Reporting window used for these email delivery measurements. | | `trend` | [GetEmailDeliverabilityTrend](#getemaildeliverabilitytrend-response-trend) | Yes | Recent changes in email delivery measurements. | | `nudge` | string or null | Yes | complaint \| bounce \| null | | `held` | number | Yes | Messages held instead of being sent. | ### GetEmailDeliverabilityQuota · response.quota | Field | Type | Required | Description | | --- | --- | --- | --- | | `sent_today` | number | Yes | Messages counted against today's sending limit. | | `limit` | number | Yes | Number of results to request per page. | | `remaining` | number | Yes | Messages remaining within the current sending allowance. | | `level` | number | Yes | Current email sending tier. | | `next_limit` | null or number | Yes | Sending allowance at the next tier. | | `clean_days_to_next` | null or number | Yes | Additional clean sending days needed before the next tier can be considered. | ### GetEmailDeliverabilityWindow · response.window | Field | Type | Required | Description | | --- | --- | --- | --- | | `days` | number | Yes | Number of days in the selected retention or reporting interval. | | `sent` | number | Yes | Messages sent in the reporting window. | | `delivered` | number | Yes | Messages with a recorded successful delivery. | | `opened` | number | Yes | Messages with a recorded open event; this is not proof a person read the content. | | `clicked` | number | Yes | Messages with a recorded link-click event. | | `bounced` | number | Yes | Messages reported as bounced by the delivery provider. | | `complained` | number | Yes | Messages associated with a recipient complaint. | | `bounce_rate` | number | Yes | Fraction of sent messages that bounced, from 0 to 1. | | `complaint_rate` | number | Yes | Fraction of sent messages with a complaint, from 0 to 1. | ### GetEmailDeliverabilityTrend · response.trend | Field | Type | Required | Description | | --- | --- | --- | --- | | `delivered` | number | Yes | Messages with a recorded successful delivery. | | `bounced` | number | Yes | Messages reported as bounced by the delivery provider. | | `complained` | number | Yes | Messages associated with a recipient complaint. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/workspace.GetEmailDeliverability' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{}' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/workspace.GetEmailDeliverability", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/workspace.GetEmailDeliverability", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "tier": "trial", "quota": { "sent_today": 25, "limit": 100, "remaining": 75, "level": 1, "next_limit": 200, "clean_days_to_next": 3 }, "state": "healthy", "paused": false, "paused_reason": null, "killed": false, "window": { "days": 7, "sent": 100, "delivered": 98, "opened": 40, "clicked": 10, "bounced": 2, "complained": 0, "bounce_rate": 0.02, "complaint_rate": 0 }, "trend": { "delivered": 98, "bounced": 2, "complained": 0 }, "nudge": null, "held": 0 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": {}, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "tier": { "description": "The trust tier.", "title": "GetEmailDeliverabilityTier", "type": "string", "enum": [ "trial", "free", "paid" ] }, "quota": { "description": "Current email sending allowance.", "title": "GetEmailDeliverabilityQuota", "type": "object", "properties": { "sent_today": { "type": "number", "description": "Messages counted against today's sending limit." }, "limit": { "type": "number", "description": "Number of results to request per page." }, "remaining": { "type": "number", "description": "Messages remaining within the current sending allowance." }, "level": { "type": "number", "description": "Current email sending tier." }, "next_limit": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Sending allowance at the next tier." }, "clean_days_to_next": { "anyOf": [ { "type": "null" }, { "type": "number" } ], "description": "Additional clean sending days needed before the next tier can be considered." } }, "required": [ "sent_today", "limit", "remaining", "level", "next_limit", "clean_days_to_next" ], "additionalProperties": false }, "state": { "description": "The send state.", "title": "GetEmailDeliverabilityState", "type": "string", "enum": [ "healthy", "approaching", "at_limit", "paused" ] }, "paused": { "type": "boolean", "description": "Whether sending is currently paused." }, "paused_reason": { "type": [ "string", "null" ], "description": "Reason sending is paused, when one is recorded." }, "killed": { "type": "boolean", "description": "Whether sending has been disabled by a protection rule." }, "window": { "description": "Reporting window used for these email delivery measurements.", "title": "GetEmailDeliverabilityWindow", "type": "object", "properties": { "days": { "type": "number", "description": "Number of days in the selected retention or reporting interval." }, "sent": { "type": "number", "description": "Messages sent in the reporting window." }, "delivered": { "type": "number", "description": "Messages with a recorded successful delivery." }, "opened": { "type": "number", "description": "Messages with a recorded open event; this is not proof a person read the content." }, "clicked": { "type": "number", "description": "Messages with a recorded link-click event." }, "bounced": { "type": "number", "description": "Messages reported as bounced by the delivery provider." }, "complained": { "type": "number", "description": "Messages associated with a recipient complaint." }, "bounce_rate": { "type": "number", "description": "Fraction of sent messages that bounced, from 0 to 1." }, "complaint_rate": { "type": "number", "description": "Fraction of sent messages with a complaint, from 0 to 1." } }, "required": [ "days", "sent", "delivered", "opened", "clicked", "bounced", "complained", "bounce_rate", "complaint_rate" ], "additionalProperties": false }, "trend": { "description": "Recent changes in email delivery measurements.", "title": "GetEmailDeliverabilityTrend", "type": "object", "properties": { "delivered": { "type": "number", "description": "Messages with a recorded successful delivery." }, "bounced": { "type": "number", "description": "Messages reported as bounced by the delivery provider." }, "complained": { "type": "number", "description": "Messages associated with a recipient complaint." } }, "required": [ "delivered", "bounced", "complained" ], "additionalProperties": false }, "nudge": { "type": [ "string", "null" ], "description": "complaint | bounce | null" }, "held": { "type": "number", "description": "Messages held instead of being sent." } }, "required": [ "tier", "quota", "state", "paused", "paused_reason", "killed", "window", "trend", "nudge", "held" ], "additionalProperties": false, "examples": [ { "tier": "trial", "quota": { "sent_today": 25, "limit": 100, "remaining": 75, "level": 1, "next_limit": 200, "clean_days_to_next": 3 }, "state": "healthy", "paused": false, "paused_reason": null, "killed": false, "window": { "days": 7, "sent": 100, "delivered": 98, "opened": 40, "clicked": 10, "bounced": 2, "complained": 0, "bounce_rate": 0.02, "complaint_rate": 0 }, "trend": { "delivered": 98, "bounced": 2, "complained": 0 }, "nudge": null, "held": 0 } ] } ``` --- # List colleagues List active colleagues with their account IDs, display names and base roles. Email addresses are excluded; administrators can use workspace.ListMembers for the detailed roster. POST https://api.brigg.app/v1/operations/workspace.ListColleagues ## Access & visibility Allow `workspace.ListColleagues` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/permissions) ## Request No parameters. Send an empty JSON object (`{}`). ## Response Returns **200 OK** with a JSON body. This operation has no continuation cursor. An empty `items` array means no matching visible results were returned. This is the active colleague roster for members with workspace access; chat-only guests cannot read it. Use account IDs for approved member delegation, not customer Person record IDs. Listing a colleague never grants the key authority to act as them. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [Colleague](#colleague-response-items) | Yes | Workspace colleagues with their account IDs and display names. This operation has no cursor pagination. | ### Colleague · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Workspace member's account ID, which can be used with Brigg-Act-As only if this key's delegation grant permits that member. | | `name` | string | Yes | Member's display name. | | `role` | string | Yes | Base role ID, such as owner, admin or member, or a workspace-defined role ID. It is not a localized label or a complete list of additive permissions. Resolve labels with workspace.ListRoles. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [List roles](/developers/reference/workspace/ListRoles) - [List members](/developers/reference/workspace/ListMembers) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/workspace.ListColleagues' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{}' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/workspace.ListColleagues", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/workspace.ListColleagues", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "account_alex", "name": "Alex Morgan", "role": "member" } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": {}, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Workspace member's account ID, which can be used with Brigg-Act-As only if this key's delegation grant permits that member.", "examples": [ "account_alex" ] }, "name": { "type": "string", "description": "Member's display name.", "examples": [ "Alex Morgan" ] }, "role": { "type": "string", "description": "Base role ID, such as owner, admin or member, or a workspace-defined role ID. It is not a localized label or a complete list of additive permissions. Resolve labels with workspace.ListRoles.", "examples": [ "member" ] } }, "required": [ "id", "name", "role" ], "additionalProperties": false, "title": "Colleague" }, "description": "Workspace colleagues with their account IDs and display names. This operation has no cursor pagination." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "id": "account_alex", "name": "Alex Morgan", "role": "member" } ] } ] } ``` --- # List join requests List pending workspace access requests for administrator review. POST https://api.brigg.app/v1/operations/workspace.ListJoinRequests ## Access & visibility Allow `workspace.ListJoinRequests` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/permissions) ## Request No parameters. Send an empty JSON object (`{}`). ## Response Returns **200 OK** with a JSON body. This operation has no continuation cursor. An empty `items` array means no matching visible results were returned. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [Join request](#join-request-response-items) | Yes | Pending requests to join the workspace. This operation has no cursor pagination. | ### Join request · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | Yes | Request ID identifying the pending workspace join request. | | `email` | string | Yes | Verified email address of the person requesting membership. | | `domain` | string | Yes | Claimed email domain through which the person requested access. | | `created_at` | number | Yes | Time access was requested, in Unix milliseconds. | | `expires_at` | number | Yes | Time the request expires, in Unix milliseconds. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/workspace.ListJoinRequests' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{}' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/workspace.ListJoinRequests", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/workspace.ListJoinRequests", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "id": "join_alex", "email": "alex@example.com", "domain": "example.com", "created_at": 1794301200000, "expires_at": 1794906000000 } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": {}, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Request ID identifying the pending workspace join request.", "examples": [ "join_alex" ] }, "email": { "type": "string", "description": "Verified email address of the person requesting membership.", "examples": [ "alex@example.com" ] }, "domain": { "type": "string", "description": "Claimed email domain through which the person requested access.", "examples": [ "example.com" ] }, "created_at": { "type": "number", "description": "Time access was requested, in Unix milliseconds.", "examples": [ 1794301200000 ] }, "expires_at": { "type": "number", "description": "Time the request expires, in Unix milliseconds.", "examples": [ 1794906000000 ] } }, "required": [ "id", "email", "domain", "created_at", "expires_at" ], "additionalProperties": false, "title": "Join request" }, "description": "Pending requests to join the workspace. This operation has no cursor pagination." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "id": "join_alex", "email": "alex@example.com", "domain": "example.com", "created_at": 1794301200000, "expires_at": 1794906000000 } ] } ] } ``` --- # List members List active workspace members and pending invitees, including their account IDs, names, emails and assigned roles. POST https://api.brigg.app/v1/operations/workspace.ListMembers ## Access & visibility Allow `workspace.ListMembers` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/permissions) ## Request No parameters. Send an empty JSON object (`{}`). ## Response Returns **200 OK** with a JSON body. This operation has no continuation cursor. An empty `items` array means no matching visible results were returned. | Field | Type | Required | Description | | --- | --- | --- | --- | | `items` | array of [Workspace member](#workspace-member-response-items) | Yes | Workspace memberships and invitations; pending distinguishes invitations from joined members. This operation has no cursor pagination. | ### Workspace member · response.items[] | Field | Type | Required | Description | | --- | --- | --- | --- | | `account_id` | string | Yes | Member's account ID. Use Brigg-Act-As only after the person joins and the key's delegation grant authorizes this active member. | | `name` | string | Yes | Member's display name. | | `email` | string or null | Yes | Member or invitee's email address. | | `role` | string | Yes | Primary workspace role identifier, such as owner, admin or member. | | `additive_roles` | array of string | Yes | Additional role identifiers contributing permissions alongside the primary role. | | `joined_at` | number | Yes | Membership join time in Unix milliseconds, when available. | | `pending` | boolean | Yes | Whether this is a pending invitation rather than a joined workspace member. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/workspace.ListMembers' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{}' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/workspace.ListMembers", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/workspace.ListMembers", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "items": [ { "account_id": "account_alex", "name": "Alex Morgan", "email": "alex@example.com", "role": "member", "additive_roles": [], "joined_at": 1794301200000, "pending": false } ] } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": {}, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "account_id": { "type": "string", "description": "Member's account ID. Use Brigg-Act-As only after the person joins and the key's delegation grant authorizes this active member.", "examples": [ "account_alex" ] }, "name": { "type": "string", "description": "Member's display name.", "examples": [ "Alex Morgan" ] }, "email": { "type": [ "string", "null" ], "description": "Member or invitee's email address.", "examples": [ "alex@example.com" ] }, "role": { "type": "string", "description": "Primary workspace role identifier, such as owner, admin or member.", "examples": [ "member" ] }, "additive_roles": { "type": "array", "items": { "type": "string" }, "description": "Additional role identifiers contributing permissions alongside the primary role.", "examples": [ [] ] }, "joined_at": { "type": "number", "description": "Membership join time in Unix milliseconds, when available.", "examples": [ 1794301200000 ] }, "pending": { "type": "boolean", "description": "Whether this is a pending invitation rather than a joined workspace member.", "examples": [ false ] } }, "required": [ "account_id", "name", "email", "role", "additive_roles", "joined_at", "pending" ], "additionalProperties": false, "title": "Workspace member" }, "description": "Workspace memberships and invitations; pending distinguishes invitations from joined members. This operation has no cursor pagination." } }, "required": [ "items" ], "additionalProperties": false, "examples": [ { "items": [ { "account_id": "account_alex", "name": "Alex Morgan", "email": "alex@example.com", "role": "member", "additive_roles": [], "joined_at": 1794301200000, "pending": false } ] } ] } ``` --- # Update personal playbook Replace your personal agent instructions with the supplied text. POST https://api.brigg.app/v1/operations/workspace.UpdatePersonalPlaybook ## Access & visibility Allow `workspace.UpdatePersonalPlaybook` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `content` | string | Yes | The COMPLETE new playbook (markdown). It REPLACES what is stored, so carry over everything that should stay. Written as standing instructions to the twin about this person, in their language. At most 10000 characters. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `status` | string | Yes | Current state reported for this item. Treat values as extensible unless an enum is declared. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. | ## Next steps [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/workspace.UpdatePersonalPlaybook' \ -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 '{ "content": "Use concise summaries and show action owners." }' ``` #### 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/workspace.UpdatePersonalPlaybook", { 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({ "content": "Use concise summaries and show action owners." }), }); 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 = { "content": "Use concise summaries and show action owners." } request = Request( "https://api.brigg.app/v1/operations/workspace.UpdatePersonalPlaybook", 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 { "status": "ok" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "content": { "type": "string", "maxLength": 10000, "description": "The COMPLETE new playbook (markdown). It REPLACES what is stored, so carry over everything that should stay. Written as standing instructions to the twin about this person, in their language." } }, "required": [ "content" ], "additionalProperties": false, "examples": [ { "content": "Use concise summaries and show action owners." } ] } ``` ```json-schema-response { "type": "object", "properties": { "status": { "type": "string", "description": "Current state reported for this item. Treat values as extensible unless an enum is declared." } }, "required": [ "status" ], "additionalProperties": false, "examples": [ { "status": "ok" } ] } ``` --- # Get privacy settings Read workspace transcript retention, host reminders and calendar disclosure notices, with available settings and the acting member's ability to change them. POST https://api.brigg.app/v1/operations/workspace.GetPrivacySettings ## Access & visibility Allow `workspace.GetPrivacySettings` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/permissions) ## Request No parameters. Send an empty JSON object (`{}`). ## Separate retention, host reminders and attendee notices These are workspace policies, not the acting member's personal preferences. Any active member can read them; can_manage tells you whether that member is a workspace owner or administrator who may change them. The API key needs the update operation as well as approved delegation to that manager. The reminder is a private prompt to the host when recording starts. The notice adds disclosure text to eligible future Google/Microsoft invitations with a conference URL and an external attendee that Brigg has permission to update. Changing settings does not prove that every provider invitation has already been updated. Use the exact values in retention_options when changing retention. A shorter policy can cause existing archived transcripts to expire; immediate deletes verbatim text after its closing summary exists. Saved summaries are separate. A deleted transcript cannot be recovered by selecting a longer policy later. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `retention` | string | Yes | Transcript policy: immediate deletes verbatim text once the closing summary exists; hours24 keeps the archive for one day; days30, days90, days180 and days365 retain it for that many days; forever has no automatic expiry. This governs transcripts, not the meeting's saved summary. | | `ai_disclosure_reminder_enabled` | boolean | Yes | Whether Brigg reminds the host at recording start to tell attendees that AI is being used. This does not notify attendees itself. | | `ai_disclosure_reminder_message` | string or null | Yes | Custom host-reminder text, or null to use the localized built-in message. | | `ai_disclosure_notice_enabled` | boolean | Yes | Whether Brigg adds the disclosure text to eligible connected-calendar invitations. This is separate from the private host reminder. | | `ai_disclosure_notice_text` | string or null | Yes | Saved invitation disclosure text, or null when unset. Enabling the notice requires nonblank saved text. | | `default_disclosure_message` | string | Yes | Built-in host-reminder text in the acting member's language (otherwise the workspace language). Used when the custom reminder is null. | | `default_disclosure_notice` | string | Yes | Suggested invitation-disclosure text in the acting member's language. Supply this or your own nonblank text when enabling a previously unset notice. | | `retention_options` | array of string | Yes | Exact supported retention IDs. These are policy values, not durations written as 30d or millisecond counts. | | `can_manage` | boolean | Yes | True for a current workspace owner or administrator. It does not grant the API key permission to call UpdatePrivacySettings. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps - [Update privacy settings](/developers/reference/workspace/UpdatePrivacySettings) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Read the workspace policy as a manager The custom reminder is unset, so the built-in localized message applies. The invitation notice is off. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/workspace.GetPrivacySettings' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{}' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/workspace.GetPrivacySettings", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/workspace.GetPrivacySettings", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "retention": "days30", "ai_disclosure_reminder_enabled": true, "ai_disclosure_reminder_message": null, "ai_disclosure_notice_enabled": false, "ai_disclosure_notice_text": null, "default_disclosure_message": "Remember to let the other meeting attendees know that AI is being used to record and summarize this meeting.", "default_disclosure_notice": "Note: AI will be used to transcribe and analyze this meeting.", "retention_options": [ "immediate", "hours24", "days30", "days90", "days180", "days365", "forever" ], "can_manage": true } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": {}, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "retention": { "type": "string", "description": "Transcript policy: immediate deletes verbatim text once the closing summary exists; hours24 keeps the archive for one day; days30, days90, days180 and days365 retain it for that many days; forever has no automatic expiry. This governs transcripts, not the meeting's saved summary." }, "ai_disclosure_reminder_enabled": { "type": "boolean", "description": "Whether Brigg reminds the host at recording start to tell attendees that AI is being used. This does not notify attendees itself." }, "ai_disclosure_reminder_message": { "type": [ "string", "null" ], "description": "Custom host-reminder text, or null to use the localized built-in message." }, "ai_disclosure_notice_enabled": { "type": "boolean", "description": "Whether Brigg adds the disclosure text to eligible connected-calendar invitations. This is separate from the private host reminder." }, "ai_disclosure_notice_text": { "type": [ "string", "null" ], "description": "Saved invitation disclosure text, or null when unset. Enabling the notice requires nonblank saved text." }, "default_disclosure_message": { "type": "string", "description": "Built-in host-reminder text in the acting member's language (otherwise the workspace language). Used when the custom reminder is null." }, "default_disclosure_notice": { "type": "string", "description": "Suggested invitation-disclosure text in the acting member's language. Supply this or your own nonblank text when enabling a previously unset notice." }, "retention_options": { "type": "array", "items": { "type": "string" }, "description": "Exact supported retention IDs. These are policy values, not durations written as 30d or millisecond counts." }, "can_manage": { "type": "boolean", "description": "True for a current workspace owner or administrator. It does not grant the API key permission to call UpdatePrivacySettings." } }, "required": [ "retention", "ai_disclosure_reminder_enabled", "ai_disclosure_reminder_message", "ai_disclosure_notice_enabled", "ai_disclosure_notice_text", "default_disclosure_message", "default_disclosure_notice", "retention_options", "can_manage" ], "additionalProperties": false, "examples": [ { "retention": "days30", "ai_disclosure_reminder_enabled": true, "ai_disclosure_reminder_message": null, "ai_disclosure_notice_enabled": false, "ai_disclosure_notice_text": null, "default_disclosure_message": "Remember to let the other meeting attendees know that AI is being used to record and summarize this meeting.", "default_disclosure_notice": "Note: AI will be used to transcribe and analyze this meeting.", "retention_options": [ "immediate", "hours24", "days30", "days90", "days180", "days365", "forever" ], "can_manage": true } ] } ``` --- # Update privacy settings Update meeting transcript retention and attendee-disclosure settings. Enabling the calendar notice requires disclosure text. POST https://api.brigg.app/v1/operations/workspace.UpdatePrivacySettings ## Access & visibility Allow `workspace.UpdatePrivacySettings` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `retention` | string | No | Transcript policy: immediate deletes verbatim text once the closing summary exists; hours24 keeps the archive for one day; days30, days90, days180 and days365 retain it for that many days; forever has no automatic expiry. This governs transcripts, not the meeting's saved summary. Allowed: `"immediate"`, `"hours24"`, `"days30"`, `"days90"`, `"days180"`, `"days365"`, `"forever"`. | | `ai_disclosure_reminder_enabled` | boolean | No | Whether Brigg reminds the host at recording start to tell attendees that AI is being used. This does not notify attendees itself. | | `ai_disclosure_reminder_message` | string or null | No | Custom reminder; null or whitespace resets to the localized built-in message. Omit to preserve the current value. | | `ai_disclosure_notice_enabled` | boolean | No | Enable or disable the invitation notice. The resulting enabled state must have nonblank text; include ai_disclosure_notice_text when none is saved. | | `ai_disclosure_notice_text` | string or null | No | Text to append to eligible invitations. Omit to preserve it; null or whitespace clears it only when the notice is disabled. | ## Separate retention, host reminders and attendee notices These are workspace policies, not the acting member's personal preferences. Any active member can read them; canManage tells you whether that member is a workspace owner or administrator who may change them. The API key needs the update operation as well as approved delegation to that manager. The reminder is a private prompt to the host when recording starts. The notice adds disclosure text to eligible future Google/Microsoft invitations with a conference URL and an external attendee that Brigg has permission to update. Changing settings does not prove that every provider invitation has already been updated. Use the exact values in retentionOptions when changing retention. A shorter policy can cause existing archived transcripts to expire; immediate deletes verbatim text after its closing summary exists. Saved summaries are separate. A deleted transcript cannot be recovered by selecting a longer policy later. ## Response Returns **200 OK** with a JSON body. Send only the settings you intend to change. Omitted settings remain unchanged. Read GetPrivacySettings after the save when you also need supported values, localized defaults or management capability. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | | `retention` | string | Yes | Transcript policy: immediate deletes verbatim text once the closing summary exists; hours24 keeps the archive for one day; days30, days90, days180 and days365 retain it for that many days; forever has no automatic expiry. This governs transcripts, not the meeting's saved summary. | | `ai_disclosure_reminder_enabled` | boolean | Yes | Whether Brigg reminds the host at recording start to tell attendees that AI is being used. This does not notify attendees itself. | | `ai_disclosure_reminder_message` | null or string | No | Custom host-reminder text, or null to use the localized built-in message. | | `ai_disclosure_notice_enabled` | boolean | Yes | Whether Brigg adds the disclosure text to eligible connected-calendar invitations. This is separate from the private host reminder. | | `ai_disclosure_notice_text` | null or string | No | Saved invitation disclosure text, or null when unset. Enabling the notice requires nonblank saved text. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 400 | `disclosure_notice_text_required` | The resulting enabled invitation notice has no text. Supply nonblank ai_disclosure_notice_text, or disable the notice when clearing it. | ## Next steps - [Get privacy settings](/developers/reference/workspace/GetPrivacySettings) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Change transcript retention Confirm the deletion implications before shortening retention. Other saved settings remain unchanged. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/workspace.UpdatePrivacySettings' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "retention": "days30" }' ``` #### TypeScript ```typescript 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/workspace.UpdatePrivacySettings", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "retention": "days30" }), }); 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 = { "retention": "days30" } request = Request( "https://api.brigg.app/v1/operations/workspace.UpdatePrivacySettings", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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, "retention": "days30", "ai_disclosure_reminder_enabled": true, "ai_disclosure_reminder_message": null, "ai_disclosure_notice_enabled": false, "ai_disclosure_notice_text": null } ``` ### Enable the invitation notice with text Supply both fields when the notice has no saved text. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/workspace.UpdatePrivacySettings' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{ "ai_disclosure_notice_enabled": true, "ai_disclosure_notice_text": "Note: AI will be used to transcribe and analyze this meeting." }' ``` #### TypeScript ```typescript 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/workspace.UpdatePrivacySettings", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({ "ai_disclosure_notice_enabled": true, "ai_disclosure_notice_text": "Note: AI will be used to transcribe and analyze this meeting." }), }); 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 = { "ai_disclosure_notice_enabled": True, "ai_disclosure_notice_text": "Note: AI will be used to transcribe and analyze this meeting." } request = Request( "https://api.brigg.app/v1/operations/workspace.UpdatePrivacySettings", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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, "retention": "days30", "ai_disclosure_reminder_enabled": true, "ai_disclosure_reminder_message": null, "ai_disclosure_notice_enabled": true, "ai_disclosure_notice_text": "Note: AI will be used to transcribe and analyze this meeting." } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "retention": { "type": "string", "enum": [ "immediate", "hours24", "days30", "days90", "days180", "days365", "forever" ], "description": "Transcript policy: immediate deletes verbatim text once the closing summary exists; hours24 keeps the archive for one day; days30, days90, days180 and days365 retain it for that many days; forever has no automatic expiry. This governs transcripts, not the meeting's saved summary." }, "ai_disclosure_reminder_enabled": { "type": "boolean", "description": "Whether Brigg reminds the host at recording start to tell attendees that AI is being used. This does not notify attendees itself." }, "ai_disclosure_reminder_message": { "anyOf": [ { "type": "string", "maxLength": 500, "description": "Custom reminder; null or whitespace resets to the localized built-in message. Omit to preserve the current value." }, { "type": "null", "description": "Custom reminder; null or whitespace resets to the localized built-in message. Omit to preserve the current value." } ], "description": "Custom reminder; null or whitespace resets to the localized built-in message. Omit to preserve the current value." }, "ai_disclosure_notice_enabled": { "type": "boolean", "description": "Enable or disable the invitation notice. The resulting enabled state must have nonblank text; include ai_disclosure_notice_text when none is saved." }, "ai_disclosure_notice_text": { "anyOf": [ { "type": "string", "maxLength": 500, "description": "Text to append to eligible invitations. Omit to preserve it; null or whitespace clears it only when the notice is disabled." }, { "type": "null", "description": "Text to append to eligible invitations. Omit to preserve it; null or whitespace clears it only when the notice is disabled." } ], "description": "Text to append to eligible invitations. Omit to preserve it; null or whitespace clears it only when the notice is disabled." } }, "additionalProperties": false, "examples": [ { "retention": "days30" } ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." }, "retention": { "type": "string", "description": "Transcript policy: immediate deletes verbatim text once the closing summary exists; hours24 keeps the archive for one day; days30, days90, days180 and days365 retain it for that many days; forever has no automatic expiry. This governs transcripts, not the meeting's saved summary." }, "ai_disclosure_reminder_enabled": { "type": "boolean", "description": "Whether Brigg reminds the host at recording start to tell attendees that AI is being used. This does not notify attendees itself." }, "ai_disclosure_reminder_message": { "description": "Custom host-reminder text, or null to use the localized built-in message.", "title": "OpenAdThreadSubtaskAgent_phase", "anyOf": [ { "type": "null", "description": "Custom host-reminder text, or null to use the localized built-in message." }, { "type": "string", "description": "Custom host-reminder text, or null to use the localized built-in message." } ] }, "ai_disclosure_notice_enabled": { "type": "boolean", "description": "Whether Brigg adds the disclosure text to eligible connected-calendar invitations. This is separate from the private host reminder." }, "ai_disclosure_notice_text": { "description": "Saved invitation disclosure text, or null when unset. Enabling the notice requires nonblank saved text.", "title": "OpenAdThreadSubtaskAgent_phase", "anyOf": [ { "type": "null", "description": "Saved invitation disclosure text, or null when unset. Enabling the notice requires nonblank saved text." }, { "type": "string", "description": "Saved invitation disclosure text, or null when unset. Enabling the notice requires nonblank saved text." } ] } }, "required": [ "ok", "retention", "ai_disclosure_reminder_enabled", "ai_disclosure_notice_enabled" ], "additionalProperties": false, "examples": [ { "ok": true, "retention": "days30", "ai_disclosure_reminder_enabled": true, "ai_disclosure_reminder_message": null, "ai_disclosure_notice_enabled": false, "ai_disclosure_notice_text": null } ] } ``` --- # List roles Read workspace roles by role ID, including their labels, origins, assignment rules and number of active members using each base role. POST https://api.brigg.app/v1/operations/workspace.ListRoles ## Access & visibility Allow `workspace.ListRoles` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/permissions) ## Request No parameters. Send an empty JSON object (`{}`). ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `roles` | map of [WorkspaceRole](#workspacerole-response-roles) | Yes | Workspace role definitions keyed by role identifier. Use the key, not the label, when interpreting a member's role. | ### WorkspaceRole · response.roles.* | Field | Type | Required | Description | | --- | --- | --- | --- | | `label` | string | No | Human-readable name of this role. | | `description` | string | No | Descriptive text. | | `chatOnly` | boolean | No | Whether this role limits the member to chat-based access. Allowed: `false`, `true`. | | `system` | boolean | Yes | Whether Brigg supplies this role as a built-in role. Allowed: `false`, `true`. | | `origin` | string | No | Where this role was defined: a bundled app, a custom definition or Brigg itself. Allowed: `"bundle"`, `"custom"`, `"system"`. | | `assignable` | boolean | Yes | Whether this role can be assigned to workspace members. Allowed: `false`, `true`. | | `memberCount` | number | Yes | Number of workspace members assigned to this role. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 401 | `invalid_key` | The workspace API key is missing, invalid or revoked. | | 403 | `forbidden` | Check the key’s operation and resource grants. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 404 | `not_found` | The requested operation or resource is not available to this credential. | | 429 | `rate_limited` | Wait for Retry-After before retrying. | ## Next steps [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/workspace.ListRoles' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ --data-raw '{}' ``` #### TypeScript ```typescript const response = await fetch("https://api.brigg.app/v1/operations/workspace.ListRoles", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({}), }); 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 payload = {} request = Request( "https://api.brigg.app/v1/operations/workspace.ListRoles", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", }, 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 { "roles": { "member": { "label": "Member", "system": true, "origin": "system", "assignable": true, "memberCount": 8 }, "admin": { "label": "Administrator", "system": true, "origin": "system", "assignable": true, "memberCount": 2 } } } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": {}, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "roles": { "type": "object", "description": "Workspace role definitions keyed by role identifier. Use the key, not the label, when interpreting a member's role.", "additionalProperties": { "title": "WorkspaceRole", "type": "object", "properties": { "label": { "type": "string", "description": "Human-readable name of this role." }, "description": { "type": "string", "description": "Descriptive text." }, "chatOnly": { "type": "boolean", "enum": [ false, true ], "description": "Whether this role limits the member to chat-based access." }, "system": { "type": "boolean", "enum": [ false, true ], "description": "Whether Brigg supplies this role as a built-in role." }, "origin": { "type": "string", "enum": [ "bundle", "custom", "system" ], "description": "Where this role was defined: a bundled app, a custom definition or Brigg itself." }, "assignable": { "type": "boolean", "enum": [ false, true ], "description": "Whether this role can be assigned to workspace members." }, "memberCount": { "type": "number", "description": "Number of workspace members assigned to this role." } }, "required": [ "system", "assignable", "memberCount" ], "additionalProperties": false } } }, "required": [ "roles" ], "additionalProperties": false, "examples": [ { "roles": { "member": { "label": "Member", "system": true, "origin": "system", "assignable": true, "memberCount": 8 }, "admin": { "label": "Administrator", "system": true, "origin": "system", "assignable": true, "memberCount": 2 } } } ] } ``` --- # Get job Read progress of document generation, CRM imports or briefing work. A completed result identifies the generated file or affected record, or reports imported record counts. Results remain subject to current access. A job awaiting input must be continued in Brigg. Retrying a start command with the same idempotency key returns the same job. POST https://api.brigg.app/v1/operations/workspace.GetJob ## Access & visibility Allow `workspace.GetJob` on your API key. **Acting member required.** Send `Brigg-Act-As` with an [approved member account ID](/developers/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](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `job_id` | string | Yes | ID returned by a supported start operation, such as FillWordTemplate or GenerateBrief. Keep the same approved acting member used to start it. At least 1 character. | ## Poll without starting duplicate work Keep `job_id` from the operation that started the work and use the same acting member when polling. This endpoint reads supported document-generation, briefing and CRM-import jobs; it does not enumerate every internal task. - `queued` or `running`: wait before polling again. `retry_at`, when present, is an earliest suggested timestamp in Unix milliseconds; it is not a duration. - `awaiting_input`: the person must continue the task in Brigg. Polling or repeating the start command does not answer that question. - `completed`: inspect `kind` and the fields in `result`. A document job returns a `file_id`; a brief job identifies a record, not the brief's body; a CRM import can report an imported count. - `failed` or `cancelled`: stop automatic polling and inspect the returned error or the task in Brigg before starting a new action. Results still require current access. A previously readable job can become unavailable after revocation or a change to the target's permissions. ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `job_id` | string | Yes | Opaque job identifier returned when the work starts. | | `kind` | string | Yes | The work this job performs. Allowed: `"document_generation"`, `"crm_import"`, `"brief"`, `"brief_action"`. | | `status` | string | Yes | Failed and cancelled are terminal. An automatically retried attempt remains queued. Awaiting_input needs a response in the task in Brigg; do not start duplicate work. Allowed: `"queued"`, `"running"`, `"awaiting_input"`, `"completed"`, `"failed"`, `"cancelled"`. | | `created_at` | integer | Yes | Time the work was accepted, in Unix milliseconds. | | `updated_at` | integer | Yes | Most recent progress change, in Unix milliseconds. | | `retry_at` | integer or null | Yes | Earliest suggested next check, in Unix milliseconds, or null when no specific time is supplied. Still poll with a delay and honor HTTP rate limits. | | `result` | [object](#response-result) or null | Yes | Completion result selected by kind. Null while unfinished or when no public result is available. A resource_id identifies a record; it is not generated content. | | `error` | [object](#response-error) or null | Yes | A terminal failure. Fix the cause and submit a new command with a new idempotency key; retrying the old command returns the same job. | ### response.result | Field | Type | Required | Description | | --- | --- | --- | --- | | `file_id` | string | No | Generated file; use documents.GetFileDownload. | | `resource_type` | string | No | Kind of the affected record. | | `resource_id` | string | No | Affected record identifier; read the record for current values. | | `imported` | integer | No | Records created or updated. | ### response.error | Field | Type | Required | Description | | --- | --- | --- | --- | | `code` | string | Yes | Machine-readable code identifying this outcome or issue. | | `message` | string | Yes | Human-readable explanation of the returned outcome. | ## Errors & retries This operation reads data. It needs no idempotency key and can be retried after a transient failure. For rate limits, follow the server’s retry guidance and back off. See [HTTP errors](/developers/http#errors) and [safe retries and limits](/developers/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. | | 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. | ## Next steps - [Get file download](/developers/reference/documents/GetFileDownload) - [Get CRM import run](/developers/reference/customers/GetCrmImportRun) - [Fill Word template](/developers/reference/documents/FillWordTemplate) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Still generating No file exists in this result yet. Wait before polling again. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/workspace.GetJob' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Brigg-Act-As: $BRIGG_ACT_AS" \ --data-raw '{ "job_id": "job_document_proposal" }' ``` #### 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 response = await fetch("https://api.brigg.app/v1/operations/workspace.GetJob", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Brigg-Act-As": actAs, }, body: JSON.stringify({ "job_id": "job_document_proposal" }), }); 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 payload = { "job_id": "job_document_proposal" } request = Request( "https://api.brigg.app/v1/operations/workspace.GetJob", 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"], }, 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 { "job_id": "job_document_proposal", "kind": "document_generation", "created_at": 1794301200000, "updated_at": 1794301260000, "retry_at": null, "result": null, "error": null, "status": "running" } ``` ### Document ready Use the returned file_id with GetFileDownload. The job response contains no temporary download credential. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/workspace.GetJob' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Brigg-Act-As: $BRIGG_ACT_AS" \ --data-raw '{ "job_id": "job_document_proposal" }' ``` #### 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 response = await fetch("https://api.brigg.app/v1/operations/workspace.GetJob", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Brigg-Act-As": actAs, }, body: JSON.stringify({ "job_id": "job_document_proposal" }), }); 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 payload = { "job_id": "job_document_proposal" } request = Request( "https://api.brigg.app/v1/operations/workspace.GetJob", 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"], }, 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 { "job_id": "job_document_proposal", "kind": "document_generation", "created_at": 1794301200000, "updated_at": 1794301260000, "retry_at": null, "result": { "file_id": "f_proposal" }, "error": null, "status": "completed" } ``` ### Generation failed A terminal failure requires inspection; do not keep polling indefinitely. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/workspace.GetJob' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Brigg-Act-As: $BRIGG_ACT_AS" \ --data-raw '{ "job_id": "job_document_proposal" }' ``` #### 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 response = await fetch("https://api.brigg.app/v1/operations/workspace.GetJob", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Brigg-Act-As": actAs, }, body: JSON.stringify({ "job_id": "job_document_proposal" }), }); 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 payload = { "job_id": "job_document_proposal" } request = Request( "https://api.brigg.app/v1/operations/workspace.GetJob", 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"], }, 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 { "job_id": "job_document_proposal", "kind": "document_generation", "created_at": 1794301200000, "updated_at": 1794301260000, "retry_at": null, "result": null, "error": { "code": "job_failed", "message": "The work stopped. Review the task in Brigg before starting it again." }, "status": "failed" } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "job_id": { "type": "string", "minLength": 1, "description": "ID returned by a supported start operation, such as FillWordTemplate or GenerateBrief. Keep the same approved acting member used to start it." } }, "required": [ "job_id" ], "additionalProperties": false, "examples": [ { "job_id": "job_document_proposal" } ] } ``` ```json-schema-response { "title": "Job", "type": "object", "additionalProperties": false, "properties": { "job_id": { "type": "string", "description": "Opaque job identifier returned when the work starts." }, "kind": { "type": "string", "enum": [ "document_generation", "crm_import", "brief", "brief_action" ], "description": "The work this job performs." }, "status": { "type": "string", "enum": [ "queued", "running", "awaiting_input", "completed", "failed", "cancelled" ], "description": "Failed and cancelled are terminal. An automatically retried attempt remains queued. Awaiting_input needs a response in the task in Brigg; do not start duplicate work." }, "created_at": { "type": "integer", "description": "Time the work was accepted, in Unix milliseconds." }, "updated_at": { "type": "integer", "description": "Most recent progress change, in Unix milliseconds." }, "retry_at": { "type": [ "integer", "null" ], "description": "Earliest suggested next check, in Unix milliseconds, or null when no specific time is supplied. Still poll with a delay and honor HTTP rate limits." }, "result": { "type": [ "object", "null" ], "additionalProperties": false, "properties": { "file_id": { "type": "string", "description": "Generated file; use documents.GetFileDownload." }, "resource_type": { "type": "string", "description": "Kind of the affected record." }, "resource_id": { "type": "string", "description": "Affected record identifier; read the record for current values." }, "imported": { "type": "integer", "description": "Records created or updated." } }, "description": "Completion result selected by kind. Null while unfinished or when no public result is available. A resource_id identifies a record; it is not generated content." }, "error": { "type": [ "object", "null" ], "properties": { "code": { "type": "string", "description": "Machine-readable code identifying this outcome or issue." }, "message": { "type": "string", "description": "Human-readable explanation of the returned outcome." } }, "required": [ "code", "message" ], "additionalProperties": false, "description": "A terminal failure. Fix the cause and submit a new command with a new idempotency key; retrying the old command returns the same job." } }, "required": [ "job_id", "kind", "status", "created_at", "updated_at", "retry_at", "result", "error" ], "examples": [ { "job_id": "job_document_proposal", "kind": "document_generation", "created_at": 1794301200000, "updated_at": 1794301260000, "retry_at": null, "result": null, "error": null, "status": "running" } ] } ``` --- # Generate company profile Generate a company profile from the workspace's website. Returns Markdown for review without saving it; use workspace.UpdateBranding to save an approved profile. Uses workspace credits. POST https://api.brigg.app/v1/operations/workspace.GenerateCompanyProfile ## Access & visibility Allow `workspace.GenerateCompanyProfile` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/permissions) ## Request No parameters. Send an empty JSON object (`{}`). ## Response Returns **200 OK** with a JSON body. The generated Markdown is returned for review; this call does not save it. Review and edit it, then pass it as profile_md to UpdateBranding. Generation reads the primary website configured in the workspace profile. | Field | Type | Required | Description | | --- | --- | --- | --- | | `profile_md` | string | Yes | Workspace company profile formatted as Markdown. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | | 400 | `no_domain` | Set the workspace's primary website in Brigg first. | | 502 | `profile_not_generated` | A profile could not be generated from the website. Retry later or provide reviewed text through UpdateBranding. | ## Next steps - [Get branding](/developers/reference/workspace/GetBranding) - [Update branding](/developers/reference/workspace/UpdateBranding) [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/workspace.GenerateCompanyProfile' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{}' ``` #### TypeScript ```typescript 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/workspace.GenerateCompanyProfile", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({}), }); 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 = {} request = Request( "https://api.brigg.app/v1/operations/workspace.GenerateCompanyProfile", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 { "profile_md": "Northstar helps small businesses organize their customer work." } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": {}, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "profile_md": { "type": "string", "description": "Workspace company profile formatted as Markdown." } }, "required": [ "profile_md" ], "additionalProperties": false, "examples": [ { "profile_md": "Northstar helps small businesses organize their customer work." } ] } ``` --- # Update workspace profile Update the workspace's name, language, billing email or primary domain. Claiming a domain requires human approval and cannot use a public email-provider domain. POST https://api.brigg.app/v1/operations/workspace.UpdateWorkspaceProfile ## Access & visibility Allow `workspace.UpdateWorkspaceProfile` on your API key. **Workspace access by default.** Private member data requires [approved member delegation](/developers/authentication#member-delegation) through `Brigg-Act-As`; the key supplies permissions while private ownership and project boundaries remain enforced. [Set up authentication](/developers/authentication) · [Choose permissions](/developers/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 | | --- | --- | --- | --- | | `name` | string | No | Display name. At least 1 character. At most 80 characters. | | `brand_name` | string or null | No | The trading name customers know the company by; empty or null clears it, and every customer-facing surface then shows `name`. | | `default_language` | string | No | Default language of the workspace. Allowed: `"no"`, `"en"`, `"sv"`, `"da"`. | | `invoice_email` | string or null | No | Empty string or null clears it. | | `domain` | string or null | No | The PRIMARY/branding domain — a bare host; empty or null clears it. Must not be a public webmail host or a domain another workspace claims. | ## Response Returns **200 OK** with a JSON body. | Field | Type | Required | Description | | --- | --- | --- | --- | | `ok` | boolean | Yes | Whether the action completed successfully. | ## 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](/developers/http#errors) and [safe retries and limits](/developers/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. If Brigg-Act-As is supplied, the key must be authorized to delegate to that member. | | 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. | ## Next steps [Download OpenAPI](/developers/openapi.json) · [Versioning & retirement](/developers/versioning) ## Examples ### Example request Fictional values. Replace IDs and business details with values from your workspace. #### cURL ```sh curl 'https://api.brigg.app/v1/operations/workspace.UpdateWorkspaceProfile' \ -H "Authorization: Bearer $BRIGG_API_KEY" \ -H 'Content-Type: application/json' \ -H "Idempotency-Key: $BRIGG_REQUEST_ID" \ --data-raw '{}' ``` #### TypeScript ```typescript 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/workspace.UpdateWorkspaceProfile", { method: "POST", headers: { Authorization: `Bearer ${process.env.BRIGG_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": requestId, // Create once per action; reuse on retries. }, body: JSON.stringify({}), }); 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 = {} request = Request( "https://api.brigg.app/v1/operations/workspace.UpdateWorkspaceProfile", data=json.dumps(payload).encode("utf-8"), headers={ "Authorization": f"Bearer {os.environ['BRIGG_API_KEY']}", "Content-Type": "application/json", "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 } ``` ## JSON schemas ```json-schema-request { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 80, "description": "Display name." }, "brand_name": { "anyOf": [ { "type": "string", "maxLength": 80 }, { "type": "string", "const": "" }, { "type": "null" } ], "description": "The trading name customers know the company by; empty or null clears it, and every customer-facing surface then shows `name`." }, "default_language": { "type": "string", "enum": [ "no", "en", "sv", "da" ], "description": "Default language of the workspace." }, "invoice_email": { "anyOf": [ { "type": "string", "format": "email" }, { "type": "string", "const": "" }, { "type": "null" } ], "description": "Empty string or null clears it." }, "domain": { "anyOf": [ { "type": "string", "maxLength": 253 }, { "type": "string", "const": "" }, { "type": "null" } ], "description": "The PRIMARY/branding domain — a bare host; empty or null clears it. Must not be a public webmail host or a domain another workspace claims." } }, "additionalProperties": false, "examples": [ {} ] } ``` ```json-schema-response { "type": "object", "properties": { "ok": { "type": "boolean", "description": "Whether the action completed successfully." } }, "required": [ "ok" ], "additionalProperties": false, "examples": [ { "ok": true } ] } ```