@wildo-ai/saas-technical-doc 1.1.1 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dist/esm/companion/application-documentation/application-administration-documentation.d.ts +52 -0
  2. package/dist/esm/companion/application-documentation/application-administration-documentation.d.ts.map +1 -0
  3. package/dist/esm/companion/application-documentation/application-administration-documentation.js +58 -0
  4. package/dist/esm/companion/application-documentation/application-administration-documentation.js.map +1 -0
  5. package/dist/esm/companion/application-documentation/application-authentication-documentation.d.ts +76 -0
  6. package/dist/esm/companion/application-documentation/application-authentication-documentation.d.ts.map +1 -0
  7. package/dist/esm/companion/application-documentation/application-authentication-documentation.js +116 -0
  8. package/dist/esm/companion/application-documentation/application-authentication-documentation.js.map +1 -0
  9. package/dist/esm/companion/application-documentation/application-connection-documentation.d.ts +87 -0
  10. package/dist/esm/companion/application-documentation/application-connection-documentation.d.ts.map +1 -0
  11. package/dist/esm/companion/application-documentation/application-connection-documentation.js +138 -0
  12. package/dist/esm/companion/application-documentation/application-connection-documentation.js.map +1 -0
  13. package/dist/esm/companion/application-documentation/application-integration-documentation.d.ts +48 -0
  14. package/dist/esm/companion/application-documentation/application-integration-documentation.d.ts.map +1 -0
  15. package/dist/esm/companion/application-documentation/application-integration-documentation.js +63 -0
  16. package/dist/esm/companion/application-documentation/application-integration-documentation.js.map +1 -0
  17. package/dist/esm/companion/application-documentation/technical-documentation-engine-content-bundle.d.ts +21 -3
  18. package/dist/esm/companion/application-documentation/technical-documentation-engine-content-bundle.d.ts.map +1 -1
  19. package/dist/esm/companion/application-documentation/technical-documentation-engine-content-bundle.js +166 -10
  20. package/dist/esm/companion/application-documentation/technical-documentation-engine-content-bundle.js.map +1 -1
  21. package/dist/esm/companion/application-documentation/technical-documentation-private-derivation.d.ts +8 -0
  22. package/dist/esm/companion/application-documentation/technical-documentation-private-derivation.d.ts.map +1 -1
  23. package/dist/esm/companion/application-documentation/technical-documentation-private-derivation.js +8 -1
  24. package/dist/esm/companion/application-documentation/technical-documentation-private-derivation.js.map +1 -1
  25. package/dist/esm/companion/index.d.ts +4 -0
  26. package/dist/esm/companion/index.d.ts.map +1 -1
  27. package/dist/esm/companion/index.js +4 -0
  28. package/dist/esm/companion/index.js.map +1 -1
  29. package/dist/esm/companion/openapi-generator.d.ts.map +1 -1
  30. package/dist/esm/companion/openapi-generator.js +9 -7
  31. package/dist/esm/companion/openapi-generator.js.map +1 -1
  32. package/dist/esm/companion/rendering/technical-documentation-docusaurus-renderer.d.ts.map +1 -1
  33. package/dist/esm/companion/rendering/technical-documentation-docusaurus-renderer.js +10 -2
  34. package/dist/esm/companion/rendering/technical-documentation-docusaurus-renderer.js.map +1 -1
  35. package/dist/esm/companion/rendering/technical-documentation-markdown-links.d.ts +28 -0
  36. package/dist/esm/companion/rendering/technical-documentation-markdown-links.d.ts.map +1 -0
  37. package/dist/esm/companion/rendering/technical-documentation-markdown-links.js +52 -0
  38. package/dist/esm/companion/rendering/technical-documentation-markdown-links.js.map +1 -0
  39. package/dist/esm/companion/rendering/technical-documentation-markdown-renderer.d.ts.map +1 -1
  40. package/dist/esm/companion/rendering/technical-documentation-markdown-renderer.js +7 -2
  41. package/dist/esm/companion/rendering/technical-documentation-markdown-renderer.js.map +1 -1
  42. package/dist/esm/companion/rendering/technical-documentation-render-model.d.ts +1 -0
  43. package/dist/esm/companion/rendering/technical-documentation-render-model.d.ts.map +1 -1
  44. package/dist/esm/companion/rendering/technical-documentation-render-model.js +91 -84
  45. package/dist/esm/companion/rendering/technical-documentation-render-model.js.map +1 -1
  46. package/dist/esm/content/application-consumer-documentation-content.techdoc.d.ts +74 -69
  47. package/dist/esm/content/application-consumer-documentation-content.techdoc.d.ts.map +1 -1
  48. package/dist/esm/content/application-consumer-documentation-content.techdoc.js +654 -1120
  49. package/dist/esm/content/application-consumer-documentation-content.techdoc.js.map +1 -1
  50. package/dist/esm/runtime/decode-jwt-claims.d.ts +7 -4
  51. package/dist/esm/runtime/decode-jwt-claims.d.ts.map +1 -1
  52. package/dist/esm/runtime/decode-jwt-claims.js +7 -4
  53. package/dist/esm/runtime/decode-jwt-claims.js.map +1 -1
  54. package/dist/esm/runtime/docs-auth-session.schemas.d.ts +16 -5
  55. package/dist/esm/runtime/docs-auth-session.schemas.d.ts.map +1 -1
  56. package/dist/esm/runtime/docs-auth-session.schemas.js +16 -5
  57. package/dist/esm/runtime/docs-auth-session.schemas.js.map +1 -1
  58. package/dist/esm/runtime/use-docs-auth-session.d.ts +9 -7
  59. package/dist/esm/runtime/use-docs-auth-session.d.ts.map +1 -1
  60. package/dist/esm/runtime/use-docs-auth-session.js +9 -7
  61. package/dist/esm/runtime/use-docs-auth-session.js.map +1 -1
  62. package/dist/tsconfig.build.tsbuildinfo +1 -1
  63. package/package.json +5 -5
  64. package/dist/esm/.builder.pid +0 -9
@@ -14,33 +14,33 @@
14
14
  export declare const APPLICATION_CONSUMER_DOCUMENTATION_AUTHORED_CONTENT_V1: readonly [{
15
15
  readonly managedPath: "get-started.md";
16
16
  readonly unitRef: "technical-documentation:unit/application-orientation";
17
- readonly sourceRefs: readonly ["saas-technical-doc:engine-content/application-orientation"];
18
- readonly markdown: "# Get started\n\nThis documentation is for people who **use, administer, integrate or operate\nthis application**. You do not need to know how the application was built, and\nyou do not need to understand every technology before choosing a path. Start\nwith the result you need.\n\n## What do you need to do?\n\n| Your goal | Begin here | You will learn |\n| --- | --- | --- |\n| Sign in, complete a second factor or recover access | [Access and identity](/access-and-identity/overview) | Which sign-in method belongs to a person, a service or a delegated client—and how to distinguish authentication from permission problems |\n| Invite a person, change access or remove access | [User administration](/user-administration) | How manual membership, roles, organization units, single sign-on and SCIM work together |\n| Connect another system or automate a process | [Integrations](/integrations) | When to use REST, webhooks, an automation platform or an agent connection |\n| Build a workflow in n8n, Zapier or Make | [Automation platforms](/integrations/automation-platforms) | How to connect through the published API, protect the credential and verify the business result |\n| Investigate a change or export security evidence | [Security and audit](/security-and-audit) | How to read the authoritative audit trail, follow correlation and operate SIEM delivery safely |\n| Understand a subscription, invoice or access delay | Look for **Billing and subscriptions** in the navigation | How billing state becomes application access and how to reconcile an asynchronous change |\n| Implement an exact request | [API reference](/api) | The current operation, field, role, request and response contract |\n\nIf **AI coding tools** appears under Integrations, the application has published\nthe MCP connection required by the Cursor, Codex and Claude Code guides. If a\nsection is absent, do not assume that its capability or administrative surface\nexists in this application.\n\n~~~mermaid\nflowchart TD\n accTitle: Choose a documentation path from the outcome you need\n accDescr: A reader starts from a human access task, an administration task, an integration task, or an operational investigation. Each path leads to a guide, then to an exact reference only when implementation details are needed.\n need[\"What outcome do you need?\"] --> person{\"A person's access?\"}\n person -->|\"Sign in or recover\"| identity[\"Access and identity\"]\n person -->|\"Invite, change or remove\"| administration[\"User administration\"]\n person -->|\"No\"| system{\"Connect or operate software?\"}\n system -->|\"Connect or automate\"| integrations[\"Integrations\"]\n system -->|\"Investigate or export evidence\"| security[\"Security and audit\"]\n identity --> contract[\"Use the exact reference when needed\"]\n administration --> contract\n integrations --> contract\n security --> contract\n~~~\n\nThe diagram is a starting map, not an access model. Opening a guide does not\ngrant a capability. The current application's navigation, visible controls and\npublished operation contracts determine what is actually available to you.\n\n## Before you change anything\n\nConfirm four things before an administrative or integration write:\n\n1. **Environment and organization** — verify that you are working in the\n intended application environment and organization.\n2. **Identity and scope** — use your own sign-in for a human task, or a dedicated\n workload credential for software. Do not borrow a broader administrator\n credential simply to make a request succeed.\n3. **Expected result** — write down the state that should change and the state\n that must remain unchanged.\n4. **Verification** — decide how you will confirm the result from the\n application's authoritative state, especially if a request times out after a\n write.\n\n## Three useful first journeys\n\n### Help a person gain the right access\n\nStart with [User administration](/user-administration). Choose manual\nadministration for an individual membership, or the SCIM journey when an\nidentity provider owns the user lifecycle. Single sign-on authenticates the\nperson; it does not by itself create the intended organization membership or\nrole.\n\n### Connect another system safely\n\nStart with [Integrations](/integrations). Choose the connection surface from\nthe direction and shape of the work:\n\n- use **REST** when your integration initiates a read or change;\n- use a **webhook** when the application should notify your receiver of a\n published event;\n- use an **automation platform** when n8n, Zapier or Make should coordinate the\n workflow;\n- use **MCP or A2A** only when the corresponding agent surface is present.\n\nProve one read with a narrowly scoped credential before enabling a write. After\nany timeout or lost response, read the authoritative state before retrying.\n\n### Investigate an unexpected result\n\nStart with [Security and audit](/security-and-audit) when you need to establish\nwho did what, in which organization, and whether the operation succeeded. Start\nwith [Troubleshoot user access](/user-administration/troubleshoot-user-access)\nwhen the symptom is a sign-in, membership, role or visibility problem. Preserve\ncorrelation identifiers and timestamps; they make a support or audit review\nmaterially faster.\n\n## Guides and references have different jobs\n\nA **guide** explains the intended outcome, prerequisites, safe sequence,\ndecisions and recovery path. The **API reference** defines exact operations,\nparameters, fields, role requirements and response schemas. Use the guide to\nchoose and operate the right journey; use the reference while implementing a\nspecific request. Do not turn an endpoint list into an operating procedure, and\ndo not treat explanatory prose as a substitute for the current operation\ncontract.\n\n## When you ask for help\n\nProvide the environment, organization, approximate time, operation or task,\ncorrelation identifier, expected result and observed result. **Never include a\npassword, API key, OAuth secret, SCIM token or session value** in a ticket,\nmessage or screenshot.";
17
+ readonly sourceRefs: readonly ["saas-technical-doc:engine-content/application-orientation", "source:companion-projection:application-connection"];
18
+ readonly markdown: "# Get started\n\nThis documentation is for the people who use, administer, integrate with or operate {{APPLICATION_NAME}}. Pick the row that matches what you need to do; each leads to a page you can act on.\n\n## What do you need to do?\n\n| You need to | Start here | You will find |\n| --- | --- | --- |\n| Sign in, set up a second factor, or get back into your account | [Access and identity](/access-and-identity/overview) | The sign-in methods, multifactor enrollment and recovery, and what a refusal means |\n| Invite someone, change what they may do, or remove them | [User administration](/user-administration) | Memberships, the roles available in this application, organization units, single sign-on and directory provisioning |\n| Call the API from your own code | [Send your first API request](/integrations/rest/send-request) | A working request in ten minutes, then the [conventions](/integrations/rest/conventions) every operation follows |\n| Be notified when something changes | [Webhooks](/integrations/webhooks) | Signed deliveries, a receiver you can run, retries and operations |\n| Build in n8n, Zapier or Make | [Automation platforms](/integrations/automation-platforms) | The exact settings for each tool |\n| Connect an AI assistant such as Cursor, Codex or Claude Code | [AI coding tools](/integrations/ai-coding-tools) | The MCP connection and what the assistant may do |\n| Investigate who did what, or export security evidence | [Security and audit](/security-and-audit) | The audit trail, exports and delivery to your SIEM |\n| Understand a plan, an invoice or why access changed | [Billing and subscriptions](/billing-and-subscriptions) | How billing state turns into access, and how to reconcile a change |\n| Look up one operation, field or role | [API reference](/api) | The exact contract of every operation, generated from the application itself |\n\nSections appear in the navigation only when this application offers the capability. If a section named above is missing, the application does not expose that capability, and no setting on your side adds it.\n\n## Three things to know before you change anything\n\n1. **Organization.** Almost everything belongs to one organization. Check which organization you are working in before you invite, change or export; the same person can be a member of several.\n2. **Identity.** Use your own account for work you do yourself and a dedicated API key or OAuth client for software. Never lend an administrator's credential to an integration to make a request succeed; give the integration the smallest role that works.\n3. **Verification.** The application is the source of truth. After an administrative change, a payment or an API write, confirm the result in the application rather than trusting a green status alone.\n\n## How the documentation is organised\n\n- **Guides** explain a task from start to finish: what you need, what to click or send, what you should see, and what to do when it fails.\n- **Reference** pages hold exact values you look up rather than read: statuses, error codes, limits, field meanings. The [API reference](/api) is generated from the running application, so it is always the current contract.\n- Every guide links to the reference it relies on, and no guide repeats a value the reference owns.\n\n## When you ask for help\n\nGive the organization, the page or operation you were using, the time, what you expected and what you saw. For an API call, add the HTTP status and the `error.correlationId` from the response; for a webhook, the delivery identifier and `jti`. Never include a password, an API key, a bearer token or another person's data.";
19
19
  }, {
20
20
  readonly managedPath: "access-and-identity/overview.md";
21
21
  readonly unitRef: "technical-documentation:unit/authentication";
22
- readonly sourceRefs: readonly ["saas-technical-doc:engine-content/authentication", "source:consumer-fact:access-authentication-methods"];
23
- readonly markdown: "# Access and identity\n\nStart by identifying **who needs access** and **whether a person is present**.\nA person should sign in with their own method. An unattended integration should\nuse its own machine credential. A third-party client acting for a person should\nuse delegated OAuth access instead of collecting the person's password.\n\nThe credential proves an identity, but it does not decide everything that\nidentity may do. The application still checks the active organization, assigned\nroles, resource visibility, feature availability and the exact operation being\nrequested.\n\n~~~mermaid\nflowchart LR\n accTitle: Choose an access method and evaluate authorization\n accDescr: A person, service, or third-party client presents the appropriate credential. The application establishes an identity, selects an organization context, and then evaluates roles and operation access.\n person[\"Person\"] --> signin[\"Sign in method\"]\n service[\"Service or automation\"] --> key[\"API key\"]\n client[\"Third-party client\"] --> oauth[\"Delegated OAuth access\"]\n signin --> identity[\"Authenticated identity\"]\n key --> identity\n oauth --> identity\n identity --> context[\"Active organization context\"]\n context --> decision[\"Roles, policy and operation access\"]\n~~~\n\nThe diagram separates two decisions. **Authentication** answers “who or what is\nmaking this request?” **Authorization** answers “may that identity perform this\noperation here?” A successful sign-in or valid API key can therefore still\nreceive a refusal.\n\n## Choose the right access journey\n\n| You need to… | Start here | Do not use |\n| --- | --- | --- |\n| Sign in and complete a required second factor | [Sign in and multifactor authentication](/access-and-identity/sign-in-and-mfa) | A shared browser session or another person’s recovery material |\n| Connect an organization identity provider | [Single sign-on](/access-and-identity/single-sign-on) | An API key or a service credential |\n| Run an unattended workload | [API keys](/access-and-identity/api-keys) | A person’s browser session |\n| Let another client act for a person | [OAuth provider and delegated access](/access-and-identity/oauth-provider) | The person’s password or an over-privileged machine key |\n\n## What a sign-in screen may offer\n\n{{CONSUMER_FACT:source:consumer-fact:access-authentication-methods#markdown}}\n\nThis inventory is not an availability promise. The sign-in screen and\nits available-method response are authoritative for the current person and\norganization.\n\n## What happens after a credential is presented\n\n1. The application validates the credential and establishes the person,\n service or delegated client identity.\n2. It resolves the active application and, when relevant, the active\n organization.\n3. It checks the roles and assignments carried by that identity.\n4. It applies the requested operation's authentication, authorization and\n visibility rules.\n5. It returns only resources visible in that scope.\n\nChanging credentials is not a valid repair for a refused operation. First find\nwhich of those five decisions failed, then correct the intended identity,\norganization, membership, role or operation assignment.\n\n## Read authentication failures correctly\n\n| Result | What it usually means | What to check first |\n| --- | --- | --- |\n| **401 Unauthorized** | The credential is absent, malformed, expired, revoked or otherwise invalid | Credential transport, expiry, status and target environment |\n| **403 Forbidden** | The identity is known but lacks a required role, assignment, entitlement or operation permission | Active organization, role and the exact operation contract |\n| **404 Not Found** | The resource does not exist or is outside the caller's visible scope | Resource identifier and organization or unit scope; do not assume hidden data exists |\n\nUse the generated API reference for the exact operation-level contract.";
22
+ readonly sourceRefs: readonly ["saas-technical-doc:engine-content/authentication", "source:companion-projection:application-authentication", "source:companion-projection:application-connection", "source:consumer-fact:access-authentication-methods"];
23
+ readonly markdown: "# Access and identity\n\nStart by identifying **who needs access** and **whether a person is present**.\nA person should sign in with their own method. An unattended integration should\nuse its own machine credential. A third-party client acting for a person should\nuse delegated OAuth access instead of collecting the person's password.\n\nThe credential proves an identity, but it does not decide everything that\nidentity may do. The application still checks the active organization, assigned\nroles, resource visibility, feature availability and the exact operation being\nrequested.\n\n~~~mermaid\nflowchart LR\n accTitle: Choose an access method and evaluate authorization\n accDescr: A person, service, or third-party client presents the appropriate credential. The application establishes an identity, selects an organization context, and then evaluates roles and operation access.\n person[\"Person\"] --> signin[\"Sign in method\"]\n service[\"Service or automation\"] --> key[\"API key\"]\n client[\"Third-party client\"] --> oauth[\"Delegated OAuth access\"]\n signin --> identity[\"Authenticated identity\"]\n key --> identity\n oauth --> identity\n identity --> context[\"Active organization context\"]\n context --> decision[\"Roles, policy and operation access\"]\n~~~\n\nThe diagram separates two decisions. **Authentication** answers “who or what is\nmaking this request?” **Authorization** answers “may that identity perform this\noperation here?” A successful sign-in or valid API key can therefore still\nreceive a refusal.\n\n## Choose the right access journey\n\n| You need to… | Start here | Do not use |\n| --- | --- | --- |\n| Sign in and complete a required second factor | [Sign in and multifactor authentication](/access-and-identity/sign-in-and-mfa) | A shared browser session or another person’s recovery material |\n| Connect an organization identity provider | [Single sign-on](/access-and-identity/single-sign-on) | An API key or a service credential |\n| Run an unattended workload | [API keys](/access-and-identity/api-keys) | A person’s browser session |\n| Let another client act for a person | [OAuth provider and delegated access](/access-and-identity/oauth-provider) | The person’s password or an over-privileged machine key |\n\n## What {{APPLICATION_NAME}} accepts to sign in\n\n{{APPLICATION_AUTHENTICATION:enabledSignInMethods}}\n\n### The full catalogue, for comparison\n\n{{CONSUMER_FACT:source:consumer-fact:access-authentication-methods#markdown}}\n\n## What happens after a credential is presented\n\n1. The application validates the credential and establishes the person,\n service or delegated client identity.\n2. It resolves the active application and, when relevant, the active\n organization.\n3. It checks the roles and assignments carried by that identity.\n4. It applies the requested operation's authentication, authorization and\n visibility rules.\n5. It returns only resources visible in that scope.\n\nChanging credentials is not a valid repair for a refused operation. First find\nwhich of those five decisions failed, then correct the intended identity,\norganization, membership, role or operation assignment.\n\n## Read authentication failures correctly\n\n| Result | What it usually means | What to check first |\n| --- | --- | --- |\n| **401 Unauthorized** | The credential is absent, malformed, expired, revoked or otherwise invalid | Credential transport, expiry, status and target environment |\n| **403 Forbidden** | The identity is known but lacks a required role, assignment, entitlement or operation permission | Active organization, role and the exact operation contract |\n| **404 Not Found** | The resource does not exist or is outside the caller's visible scope | Resource identifier and organization or unit scope; do not assume hidden data exists |\n\nUse the generated API reference for the exact operation-level contract.";
24
24
  }, {
25
25
  readonly managedPath: "access-and-identity/sign-in-and-mfa.md";
26
26
  readonly unitRef: "technical-documentation:unit/sign-in-and-mfa";
27
- readonly sourceRefs: readonly ["saas-technical-doc:engine-content/sign-in-and-mfa", "source:consumer-fact:access-authentication-methods"];
28
- readonly markdown: "# Sign in and multifactor authentication\n\nUse your own sign-in method and complete every factor the application requires\nfor the current organization. A successful sign-in creates your session; it\ndoes not copy access from another person or organization.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Know the application environment and organization you intend to use, and have control of your own offered credential and recovery method | Your own session starts in the intended organization, required factors are satisfied and an expected application action succeeds without borrowed access |\n\n## Keep identity proof and access separate\n\n| Decision | What answers it | If it fails |\n| --- | --- | --- |\n| Which sign-in methods can this person use now? | The methods offered on the current sign-in screen | Use an offered method or the supported recovery path; do not guess an unavailable method |\n| Has the person proved control of enough factors? | The current sign-in/enrollment challenge | Complete the required factor or recover it through the person's own account |\n| Which organization is active? | The organization selected after identity is established | Select or correct the intended membership |\n| May this person perform the requested action? | Active membership, roles, feature state and the exact operation contract | Diagnose authorization separately from sign-in |\n\n~~~mermaid\nflowchart TD\n accTitle: Complete sign-in and any required second factor\n accDescr: The application presents available methods. The person completes a first factor, completes a required second-factor challenge or enrollment, and then confirms the organization used for authorization.\n start[\"Open sign-in\"] --> offered[\"Read available methods\"]\n offered --> primary[\"Complete first factor or SSO\"]\n primary --> challenge{\"Second factor required?\"}\n challenge -->|\"Yes\"| mfa[\"Complete or enroll a factor\"]\n challenge -->|\"No\"| session[\"Start session\"]\n mfa --> session\n session --> context[\"Confirm organization\"]\n~~~\n\nThe flow ends at organization confirmation because authentication and\nauthorization are separate. A correct password, passkey or provider response\ncan start a session while the selected organization or role still refuses the\nperson's intended work.\n\n## Follow the sign-in journey\n\n| Your next task | Start here | Successful result |\n| --- | --- | --- |\n| Start a session with an offered method | [Complete sign-in](/access-and-identity/complete-sign-in) | The person completes the intended method and enters the correct organization |\n| Enroll, replace or recover a factor | [Enroll and recover multifactor authentication](/access-and-identity/mfa-enrollment-and-recovery) | The person controls a usable factor and stores recovery material safely |\n| Investigate a failed sign-in | [Troubleshoot sign-in](/access-and-identity/sign-in-troubleshoot) | Authentication, organization and authorization failures are distinguished without borrowing credentials |\n\n{{CONSUMER_FACT:source:consumer-fact:access-authentication-methods#markdown}}\n\nThis is the supported method inventory, not proof that every method is enabled.\nThe sign-in screen is authoritative for this person and organization.\n\n## Use the safest available path\n\n- Use your **own offered method**. Never ask an administrator to lend a session\n or sign in on your behalf.\n- Treat a second-factor prompt you did not initiate as suspicious. Reject it and\n use the recovery/incident process.\n- Keep recovery codes and enrolled-device secrets separate from the primary\n credential.\n- After signing in, verify the organization and one expected action before\n continuing with sensitive work.\n\nWhen support is needed, provide environment, organization, method, failed\nstage, approximate time and sanitized error text. Exclude passwords, one-time\ncodes, recovery values, provider assertions and session cookies.";
27
+ readonly sourceRefs: readonly ["saas-technical-doc:engine-content/sign-in-and-mfa", "source:companion-projection:application-authentication", "source:consumer-fact:access-authentication-methods"];
28
+ readonly markdown: "# Sign in and multifactor authentication\n\nUse your own sign-in method and complete every factor the application requires\nfor the current organization. A successful sign-in creates your session; it\ndoes not copy access from another person or organization.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Know the application environment and organization you intend to use, and have control of your own offered credential and recovery method | Your own session starts in the intended organization, required factors are satisfied and an expected application action succeeds without borrowed access |\n\n## Keep identity proof and access separate\n\n| Decision | What answers it | If it fails |\n| --- | --- | --- |\n| Which sign-in methods can this person use now? | The methods offered on the current sign-in screen | Use an offered method or the supported recovery path; do not guess an unavailable method |\n| Has the person proved control of enough factors? | The current sign-in/enrollment challenge | Complete the required factor or recover it through the person's own account |\n| Which organization is active? | The organization selected after identity is established | Select or correct the intended membership |\n| May this person perform the requested action? | Active membership, roles, feature state and the exact operation contract | Diagnose authorization separately from sign-in |\n\n~~~mermaid\nflowchart TD\n accTitle: Complete sign-in and any required second factor\n accDescr: The application presents available methods. The person completes a first factor, completes a required second-factor challenge or enrollment, and then confirms the organization used for authorization.\n start[\"Open sign-in\"] --> offered[\"Read available methods\"]\n offered --> primary[\"Complete first factor or SSO\"]\n primary --> challenge{\"Second factor required?\"}\n challenge -->|\"Yes\"| mfa[\"Complete or enroll a factor\"]\n challenge -->|\"No\"| session[\"Start session\"]\n mfa --> session\n session --> context[\"Confirm organization\"]\n~~~\n\nThe flow ends at organization confirmation because authentication and\nauthorization are separate. A correct password, passkey or provider response\ncan start a session while the selected organization or role still refuses the\nperson's intended work.\n\n## What this application requires of you\n\n{{APPLICATION_AUTHENTICATION:enabledSignInMethods}}\n\nA second factor is a separate decision from the method that starts the sign-in:\n\n{{APPLICATION_AUTHENTICATION:multifactorPolicy}}\n\nIf a password is one of the methods above, it must satisfy these rules:\n\n{{APPLICATION_AUTHENTICATION:passwordRules}}\n\n## How long a session lasts, and what failed attempts cost\n\n{{APPLICATION_AUTHENTICATION:sessionAndLockout}}\n\n## Follow the sign-in journey\n\n| Your next task | Start here | Successful result |\n| --- | --- | --- |\n| Start a session with an offered method | [Complete sign-in](/access-and-identity/complete-sign-in) | The person completes the intended method and enters the correct organization |\n| Enroll, replace or recover a factor | [Enroll and recover multifactor authentication](/access-and-identity/mfa-enrollment-and-recovery) | The person controls a usable factor and stores recovery material safely |\n| Investigate a failed sign-in | [Troubleshoot sign-in](/access-and-identity/sign-in-troubleshoot) | Authentication, organization and authorization failures are distinguished without borrowing credentials |\n\n{{CONSUMER_FACT:source:consumer-fact:access-authentication-methods#markdown}}\n\nThis is the supported method inventory, not proof that every method is enabled.\nThe sign-in screen is authoritative for this person and organization.\n\n## Use the safest available path\n\n- Use your **own offered method**. Never ask an administrator to lend a session\n or sign in on your behalf.\n- Treat a second-factor prompt you did not initiate as suspicious. Reject it and\n use the recovery/incident process.\n- Keep recovery codes and enrolled-device secrets separate from the primary\n credential.\n- After signing in, verify the organization and one expected action before\n continuing with sensitive work.\n\nWhen support is needed, provide environment, organization, method, failed\nstage, approximate time and sanitized error text. Exclude passwords, one-time\ncodes, recovery values, provider assertions and session cookies.";
29
29
  }, {
30
30
  readonly managedPath: "access-and-identity/complete-sign-in.md";
31
31
  readonly unitRef: "technical-documentation:unit/complete-sign-in";
32
32
  readonly sourceRefs: readonly ["saas-technical-doc:engine-content/complete-sign-in", "source:consumer-fact:access-authentication-methods"];
33
- readonly markdown: "# Complete sign-in\n\nStart from the current application's sign-in page and use a method it offers for\nthe intended person and organization.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Confirm the application environment and intended organization, and use only a credential belonging to the person signing in | The person completes the offered method, satisfies any required challenge and starts a session in the correct organization |\n\n~~~mermaid\nsequenceDiagram\n accTitle: Complete a person-owned sign-in and verify the resulting context\n accDescr: The person starts from the application, chooses an offered method, proves the required first and second factors, receives a session, selects the intended organization and verifies an ordinary application action.\n participant Person\n participant App as Application\n participant Method as Credential or identity provider\n Person->>App: Open the intended environment's sign-in page\n App-->>Person: Offer methods available for this context\n Person->>Method: Complete selected first factor\n Method-->>App: Return verified result\n App-->>Person: Request second factor when policy requires it\n Person->>App: Complete challenge or verified enrollment\n App-->>Person: Start session\n Person->>App: Select organization and perform expected action\n~~~\n\nStart from the application so the correct environment, return destination and\norganization-aware methods are used. A link or callback copied from another\nenvironment is not a valid shortcut.\n\n## Use an offered method\n\n{{CONSUMER_FACT:source:consumer-fact:access-authentication-methods#markdown}}\n\nA **first factor** establishes the initial identity—for example a password,\npasskey or organization SSO connection when offered. A **second factor** is an\nadditional proof required by policy. Some methods can serve in either position;\nfollow the order presented for this attempt.\n\n1. Open the sign-in page for the intended environment and verify the expected\n application identity before entering a credential.\n2. Choose a method currently offered to this person and organization. A method\n from the support inventory that is absent here is not available for this attempt.\n3. Complete the first factor or organization SSO journey using the person's own\n credential and device.\n4. Complete a required second-factor challenge. If enrollment is requested,\n finish its verification and save recovery material before continuing.\n5. After the session starts, confirm the displayed person and select the\n intended organization.\n6. Perform one ordinary expected action and verify the resulting resource or\n state in that organization.\n\n## Confirm more than the redirect\n\n| Check | Expected observation |\n| --- | --- |\n| Session | The application recognizes the intended person without asking for somebody else's credential |\n| Organization | The active organization is the one where the person has the intended membership |\n| Allowed action | One ordinary action permitted by the person's role succeeds |\n| Refused action | An operation outside the intended authority remains refused |\n\nThe refusal check is important for administrators and support staff: it proves\nthat solving sign-in did not accidentally broaden the person's access.\n\nAuthentication can succeed while an operation remains unauthorized. If the\nperson enters the wrong organization or lacks a role, correct that relationship\nrather than repeating sign-in with a broader identity.\n\nIf the journey fails, preserve the method, stage, environment, organization,\ntime and sanitized message. Use [Troubleshoot sign-in](/access-and-identity/sign-in-troubleshoot)\nor the offered recovery path. Never include the password, one-time code,\nrecovery value, full provider response or session cookie in support evidence.";
33
+ readonly markdown: "# Complete sign-in\n\nStart from the current application's sign-in page and use a method it offers for\nthe intended person and organization.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Confirm the application environment and intended organization, and use only a credential belonging to the person signing in | The person completes the offered method, satisfies any required challenge and starts a session in the correct organization |\n\n~~~mermaid\nsequenceDiagram\n accTitle: Complete a person-owned sign-in and verify the resulting context\n accDescr: The person starts from the application, chooses an offered method, proves the required first and second factors, receives a session, selects the intended organization and verifies an ordinary application action.\n participant Person\n participant App as Application\n participant Method as Credential or identity provider\n Person->>App: Open the intended environment's sign-in page\n App-->>Person: Offer methods available for this context\n Person->>Method: Complete selected first factor\n Method-->>App: Return verified result\n App-->>Person: Request second factor when policy requires it\n Person->>App: Complete challenge or verified enrollment\n App-->>Person: Start session\n Person->>App: Select organization and perform expected action\n~~~\n\nStart from the application so the correct environment, return destination and\norganization-aware methods are used. A link or callback copied from another\nenvironment is not a valid shortcut.\n\n## Use an offered method\n\n{{CONSUMER_FACT:source:consumer-fact:access-authentication-methods#markdown}}\n\nA **first factor** establishes the initial identity—for example a password,\npasskey or organization SSO connection when offered. A **second factor** is an\nadditional proof required by policy. Some methods can serve in either position;\nfollow the order presented for this attempt.\n\n1. Open the sign-in page for the intended environment and verify the expected\n application identity before entering a credential.\n2. Choose a method currently offered to this person and organization. A method\n from the catalogue that is absent from the sign-in screen is not available for\n this attempt.\n3. Complete the first factor or organization SSO journey using the person's own\n credential and device.\n4. Complete a required second-factor challenge. If enrollment is requested,\n finish its verification and save recovery material before continuing.\n5. After the session starts, confirm the displayed person and select the\n intended organization.\n6. Perform one ordinary expected action and verify the resulting resource or\n state in that organization.\n\n## Confirm more than the redirect\n\n| Check | Expected observation |\n| --- | --- |\n| Session | The application recognizes the intended person without asking for somebody else's credential |\n| Organization | The active organization is the one where the person has the intended membership |\n| Allowed action | One ordinary action permitted by the person's role succeeds |\n| Refused action | An operation outside the intended authority remains refused |\n\nThe refusal check is important for administrators and support staff: it proves\nthat solving sign-in did not accidentally broaden the person's access.\n\nAuthentication can succeed while an operation remains unauthorized. If the\nperson enters the wrong organization or lacks a role, correct that relationship\nrather than repeating sign-in with a broader identity.\n\nIf the journey fails, preserve the method, stage, environment, organization,\ntime and sanitized message. Use [Troubleshoot sign-in](/access-and-identity/sign-in-troubleshoot)\nor the offered recovery path. Never include the password, one-time code,\nrecovery value, full provider response or session cookie in support evidence.";
34
34
  }, {
35
35
  readonly managedPath: "access-and-identity/mfa-enrollment-and-recovery.md";
36
36
  readonly unitRef: "technical-documentation:unit/mfa-enrollment-and-recovery";
37
- readonly sourceRefs: readonly ["saas-technical-doc:engine-content/mfa-enrollment-and-recovery"];
38
- readonly markdown: "# Enroll and recover multifactor authentication\n\nUse multifactor authentication with a factor controlled by the person signing\nin. Enrollment creates that relationship; a challenge proves control during a\nspecific attempt; recovery restores access when an enrolled factor is\nunavailable. The application decides which factors it offers for the current\nperson and organization—do not assume that a method seen elsewhere is available\nhere.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Use the person's own session, have the device or inbox needed by the offered method, and choose a protected place for recovery material | The new factor is verified, a fresh challenge succeeds and recovery material is stored separately from the primary credential |\n\n~~~mermaid\nflowchart TD\n accTitle: Enroll a factor and preserve a safe recovery path\n accDescr: The person chooses a factor offered by the application, completes setup and verification, stores recovery material separately, proves the factor in a new challenge, and uses recovery only when the normal factor is unavailable.\n offered[\"Application offers an allowed factor\"] --> setup[\"Person starts enrollment\"]\n setup --> verify[\"Verify control of the factor\"]\n verify --> stored[\"Store recovery material separately\"]\n stored --> proof[\"Complete a fresh challenge\"]\n proof --> ready[\"Factor is ready for sign-in or step-up\"]\n proof -. \"Factor unavailable\" .-> recovery[\"Use one approved recovery path\"]\n recovery --> replace[\"Enroll and verify a replacement\"]\n~~~\n\nThe important boundary is **verified enrollment**. Starting setup or scanning a\ncode is not enough: the factor becomes dependable only after the application\naccepts the verification step.\n\n## Choose only a method the application offers\n\nA factor may be an authenticator-app code, a passkey, a text-message code or an\nemail code. Its availability and whether it satisfies the current policy can\nvary by person and organization. Follow the method name and instructions shown\nfor this journey. When a stronger second factor is required, an email code alone\nmay not be accepted.\n\n## Enroll a factor safely\n\nWhen the application requires enrollment:\n\n1. Confirm that the displayed account and organization are the intended ones.\n2. Start one of the factor methods offered on that screen.\n3. Complete setup on a device, authenticator or contact channel controlled by\n the person signing in.\n4. Enter or approve the verification requested by the application.\n5. Save any recovery material in a protected location controlled by that\n person, separate from the primary credential.\n6. Complete a fresh challenge before treating enrollment as finished.\n\nWhen **authenticator-app codes (TOTP)** are offered, setup can present a QR code\nor secret plus a set of backup codes. The application stores only protected\nrepresentations of those backup codes after setup. Copy them once into the\napproved recovery store; never photograph the QR code or paste the secret into\na ticket.\n\n## Complete a challenge\n\nUse a current code, approval or device prompt for this sign-in attempt. A one-\ntime value is not a reusable password. Never forward it to another person or\napprove an unexpected request. Start a fresh challenge if the value has expired\nor belongs to an earlier attempt. A valid authenticator-app code cannot be\nreused for a second protected action in the same time window, and a backup code\nis consumed when it succeeds.\n\n> **An unexpected prompt is an incident signal.** Reject it, change the primary\n> credential if compromise is plausible, replace the affected factor and review\n> the application's available session and audit evidence.\n\n## Recover or replace a factor\n\nChoose the narrowest available recovery path:\n\n| What the person still controls | Safe recovery path |\n| --- | --- |\n| The enrolled factor | Sign in normally, then add and verify a replacement before removing the old factor |\n| A valid backup code | Use it once, sign in, then replace the unavailable factor and refresh the stored recovery set when offered |\n| Another factor accepted by the current policy | Use that factor, then manage the unavailable method from the person's own session |\n| No accepted factor or recovery material | Use the application's account-recovery or approved support process; do not ask for an MFA bypass |\n\nChanging or removing an authentication method may require fresh\nre-authentication, may be disabled by policy, and must be refused when it would\nremove the person's only usable factor while multifactor authentication remains\nrequired. Complete the replacement first.\n\nAfter suspected compromise, replace the factor and review active sessions and\nrecent access evidence. Do not weaken the organization's policy, lend an\nadministrator session or add a broad role merely to restore convenience.\n\n> **Recovery material is a credential.** Treat a recovery code, backup factor or\n> recovery artifact with the same care as the factor it replaces.\n\n## What to provide when recovery fails\n\nProvide the environment, organization, approximate time, factor type, stage\nthat failed and sanitized error text. Never provide the factor secret, QR code,\none-time value, backup code, password or session cookie.";
37
+ readonly sourceRefs: readonly ["saas-technical-doc:engine-content/mfa-enrollment-and-recovery", "source:companion-projection:application-authentication"];
38
+ readonly markdown: "# Enroll and recover multifactor authentication\n\nUse multifactor authentication with a factor controlled by the person signing\nin. Enrollment creates that relationship; a challenge proves control during a\nspecific attempt; recovery restores access when an enrolled factor is\nunavailable. The application decides which factors it offers for the current\nperson and organization—do not assume that a method seen elsewhere is available\nhere.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Use the person's own session, have the device or inbox needed by the offered method, and choose a protected place for recovery material | The new factor is verified, a fresh challenge succeeds and recovery material is stored separately from the primary credential |\n\n## What this application asks for, and what enrolment gives you\n\n{{APPLICATION_AUTHENTICATION:multifactorPolicy}}\n\n~~~mermaid\nflowchart TD\n accTitle: Enroll a factor and preserve a safe recovery path\n accDescr: The person chooses a factor offered by the application, completes setup and verification, stores recovery material separately, proves the factor in a new challenge, and uses recovery only when the normal factor is unavailable.\n offered[\"Application offers an allowed factor\"] --> setup[\"Person starts enrollment\"]\n setup --> verify[\"Verify control of the factor\"]\n verify --> stored[\"Store recovery material separately\"]\n stored --> proof[\"Complete a fresh challenge\"]\n proof --> ready[\"Factor is ready for sign-in or step-up\"]\n proof -. \"Factor unavailable\" .-> recovery[\"Use one approved recovery path\"]\n recovery --> replace[\"Enroll and verify a replacement\"]\n~~~\n\nThe important boundary is **verified enrollment**. Starting setup or scanning a\ncode is not enough: the factor becomes dependable only after the application\naccepts the verification step.\n\n## Choose only a method the application offers\n\nA factor may be an authenticator-app code, a passkey, a text-message code or an\nemail code. Its availability and whether it satisfies the current policy can\nvary by person and organization. Follow the method name and instructions shown\nfor this journey. When a stronger second factor is required, an email code alone\nmay not be accepted.\n\n## Enroll a factor safely\n\nWhen the application requires enrollment:\n\n1. Confirm that the displayed account and organization are the intended ones.\n2. Start one of the factor methods offered on that screen.\n3. Complete setup on a device, authenticator or contact channel controlled by\n the person signing in.\n4. Enter or approve the verification requested by the application.\n5. Save any recovery material in a protected location controlled by that\n person, separate from the primary credential.\n6. Complete a fresh challenge before treating enrollment as finished.\n\nWhen **authenticator-app codes (TOTP)** are offered, setup can present a QR code\nor secret plus a set of backup codes. The application stores only protected\nrepresentations of those backup codes after setup. Copy them once into the\napproved recovery store; never photograph the QR code or paste the secret into\na ticket.\n\n## Complete a challenge\n\nUse a current code, approval or device prompt for this sign-in attempt. A one-\ntime value is not a reusable password. Never forward it to another person or\napprove an unexpected request. Start a fresh challenge if the value has expired\nor belongs to an earlier attempt. A valid authenticator-app code cannot be\nreused for a second protected action in the same time window, and a backup code\nis consumed when it succeeds.\n\n> **An unexpected prompt is an incident signal.** Reject it, change the primary\n> credential if compromise is plausible, replace the affected factor and review\n> the application's available session and audit evidence.\n\n## Recover or replace a factor\n\nChoose the narrowest available recovery path:\n\n| What the person still controls | Safe recovery path |\n| --- | --- |\n| The enrolled factor | Sign in normally, then add and verify a replacement before removing the old factor |\n| A valid backup code | Use it once, sign in, then replace the unavailable factor and refresh the stored recovery set when offered |\n| Another factor accepted by the current policy | Use that factor, then manage the unavailable method from the person's own session |\n| No accepted factor or recovery material | Use the application's account-recovery or approved support process; do not ask for an MFA bypass |\n\nChanging or removing an authentication method may require fresh\nre-authentication, may be disabled by policy, and must be refused when it would\nremove the person's only usable factor while multifactor authentication remains\nrequired. Complete the replacement first.\n\nAfter suspected compromise, replace the factor and review active sessions and\nrecent access evidence. Do not weaken the organization's policy, lend an\nadministrator session or add a broad role merely to restore convenience.\n\n> **Recovery material is a credential.** Treat a recovery code, backup factor or\n> recovery artifact with the same care as the factor it replaces.\n\n## What to provide when recovery fails\n\nProvide the environment, organization, approximate time, factor type, stage\nthat failed and sanitized error text. Never provide the factor secret, QR code,\none-time value, backup code, password or session cookie.";
39
39
  }, {
40
40
  readonly managedPath: "access-and-identity/sign-in-troubleshoot.md";
41
41
  readonly unitRef: "technical-documentation:unit/sign-in-troubleshoot";
42
42
  readonly sourceRefs: readonly ["saas-technical-doc:engine-content/sign-in-troubleshoot"];
43
- readonly markdown: "# Troubleshoot sign-in\n\nFind the stage that failed before changing a credential or a person's access.\nA sign-in problem happens before the application establishes a session; an\norganization or permission problem happens after the person is known.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Preserve the environment, organization, approximate time and sanitized error text | You can name the failed stage and take one narrow corrective action without borrowing or broadening access |\n\n~~~mermaid\nflowchart TD\n accTitle: Diagnose sign-in without hiding the original problem\n accDescr: The reviewer checks whether the expected method is offered, whether the credential and second factor succeed, whether a session starts in the intended organization, and whether the requested action is authorized.\n start[\"Person cannot complete the intended task\"] --> offered{\"Expected sign-in method offered?\"}\n offered -->|No| availability[\"Check environment, organization and offered methods\"]\n offered -->|Yes| credential{\"Credential or provider journey accepted?\"}\n credential -->|No| authentication[\"Use a fresh attempt or supported recovery\"]\n credential -->|Yes| session{\"Session starts?\"}\n session -->|No| challenge[\"Check second factor, enrollment and lockout message\"]\n session -->|Yes| scope{\"Correct organization and action available?\"}\n scope -->|No| authorization[\"Check membership, role and operation contract\"]\n scope -->|Yes| resolved[\"Repeat the original task and confirm success\"]\n~~~\n\nThe diagram prevents a common mistake: changing a role cannot repair a rejected\npassword, and resetting a password cannot repair membership in the wrong\norganization.\n\n## Start with three questions\n\n1. **Where is the person signing in?** Confirm the application environment and\n organization before comparing methods or configuration.\n2. **How far did the journey progress?** Distinguish method selection,\n credential/provider validation, second-factor challenge, session creation\n and the first application action.\n3. **What changed recently?** Check a new device, factor replacement, identity-\n provider change, invitation, membership, role or organization selection.\n\n| Symptom | Check | Safe next step |\n| --- | --- | --- |\n| The expected method is absent | Environment, organization and methods actually offered | Use an offered method or ask the administrator to verify sign-in configuration |\n| A password, provider response or challenge is rejected | Whether it belongs to this person, environment and current attempt | Start one fresh attempt; use supported recovery rather than repeated guessing |\n| The account reports a lockout or too many attempts | The exact message and time of the last attempt | Stop retrying, wait for the stated recovery path or ask an administrator to review the event |\n| Enrollment is required | Which factor methods are offered and whether setup was verified | Complete one offered method and retain recovery material before continuing |\n| Sign-in succeeds but the wrong organization opens | Active organization and membership | Select or correct the intended organization |\n| Sign-in succeeds but an action is refused | Membership state, role and exact operation | Diagnose authorization instead of repeating authentication |\n| A factor is lost or suspected compromised | Recovery path, account ownership and active sessions | Recover or replace the factor and review recent access |\n\n## Read the result without guessing\n\n- A missing or rejected credential is an **authentication** problem.\n- A completed sign-in followed by a refusal is usually an **authorization or\n organization-scope** problem.\n- A resource that appears missing can be genuinely absent or outside the\n person's visible scope. Do not confirm hidden data from the error alone.\n- A method listed in the application's support inventory is not necessarily\n enabled for this person and organization. The current sign-in screen is the\n availability evidence.\n\nNever use an administrator account, another person's session or a machine\ncredential to make a user action succeed. That hides the real problem and\ndestroys reliable attribution.\n\n## Escalate with safe evidence\n\nProvide the environment, organization, approximate time, sign-in method,\nfailed stage, sanitized message and any correlation identifier. Say whether the\nperson can sign in to another organization and whether another affected person\nsees the same symptom. Never request a password, provider assertion, one-time\ncode, recovery value, API key or session cookie in a support ticket.";
43
+ readonly markdown: "# Troubleshoot sign-in\n\nFind the stage that failed before changing a credential or a person's access.\nA sign-in problem happens before the application establishes a session; an\norganization or permission problem happens after the person is known.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Preserve the environment, organization, approximate time and sanitized error text | You can name the failed stage and take one narrow corrective action without borrowing or broadening access |\n\n~~~mermaid\nflowchart TD\n accTitle: Diagnose sign-in without hiding the original problem\n accDescr: The reviewer checks whether the expected method is offered, whether the credential and second factor succeed, whether a session starts in the intended organization, and whether the requested action is authorized.\n start[\"Person cannot complete the intended task\"] --> offered{\"Expected sign-in method offered?\"}\n offered -->|No| availability[\"Check environment, organization and offered methods\"]\n offered -->|Yes| credential{\"Credential or provider journey accepted?\"}\n credential -->|No| authentication[\"Use a fresh attempt or supported recovery\"]\n credential -->|Yes| session{\"Session starts?\"}\n session -->|No| challenge[\"Check second factor, enrollment and lockout message\"]\n session -->|Yes| scope{\"Correct organization and action available?\"}\n scope -->|No| authorization[\"Check membership, role and operation contract\"]\n scope -->|Yes| resolved[\"Repeat the original task and confirm success\"]\n~~~\n\nThe diagram prevents a common mistake: changing a role cannot repair a rejected\npassword, and resetting a password cannot repair membership in the wrong\norganization.\n\n## Start with three questions\n\n1. **Where is the person signing in?** Confirm the application environment and\n organization before comparing methods or configuration.\n2. **How far did the journey progress?** Distinguish method selection,\n credential/provider validation, second-factor challenge, session creation\n and the first application action.\n3. **What changed recently?** Check a new device, factor replacement, identity-\n provider change, invitation, membership, role or organization selection.\n\n| Symptom | Check | Safe next step |\n| --- | --- | --- |\n| The expected method is absent | Environment, organization and methods actually offered | Use an offered method or ask the administrator to verify sign-in configuration |\n| A password, provider response or challenge is rejected | Whether it belongs to this person, environment and current attempt | Start one fresh attempt; use supported recovery rather than repeated guessing |\n| The account reports a lockout or too many attempts | The exact message and time of the last attempt | Stop retrying, wait for the stated recovery path or ask an administrator to review the event |\n| Enrollment is required | Which factor methods are offered and whether setup was verified | Complete one offered method and retain recovery material before continuing |\n| Sign-in succeeds but the wrong organization opens | Active organization and membership | Select or correct the intended organization |\n| Sign-in succeeds but an action is refused | Membership state, role and exact operation | Diagnose authorization instead of repeating authentication |\n| A factor is lost or suspected compromised | Recovery path, account ownership and active sessions | Recover or replace the factor and review recent access |\n\n## Read the result without guessing\n\n- A missing or rejected credential is an **authentication** problem.\n- A completed sign-in followed by a refusal is usually an **authorization or\n organization-scope** problem.\n- A resource that appears missing can be genuinely absent or outside the\n person's visible scope. Do not confirm hidden data from the error alone.\n- A method listed in the catalogue is not necessarily enabled for this person and\n organization. The current sign-in screen is the availability evidence.\n\nNever use an administrator account, another person's session or a machine\ncredential to make a user action succeed. That hides the real problem and\ndestroys reliable attribution.\n\n## Escalate with safe evidence\n\nProvide the environment, organization, approximate time, sign-in method,\nfailed stage, sanitized message and any correlation identifier. Say whether the\nperson can sign in to another organization and whether another affected person\nsees the same symptom. Never request a password, provider assertion, one-time\ncode, recovery value, API key or session cookie in a support ticket.";
44
44
  }, {
45
45
  readonly managedPath: "access-and-identity/single-sign-on.md";
46
46
  readonly unitRef: "technical-documentation:unit/single-sign-on";
@@ -104,8 +104,8 @@ export declare const APPLICATION_CONSUMER_DOCUMENTATION_AUTHORED_CONTENT_V1: rea
104
104
  }, {
105
105
  readonly managedPath: "user-administration.md";
106
106
  readonly unitRef: "technical-documentation:unit/user-administration";
107
- readonly sourceRefs: readonly ["saas-technical-doc:engine-content/user-administration", "source:consumer-fact:organization-membership-administration"];
108
- readonly markdown: "# User administration\n\nManage the people who can use your organization and the access they have. Start\nwith the task in front of you: invite someone, change their access, or stop\ntheir access. Most organizations manage people directly in the application. If\nyour company uses an identity directory, it may instead keep the user list in\nsync automatically.\n\n~~~mermaid\nflowchart LR\n accTitle: Choose manual or directory-managed user administration\n accDescr: The administrator decides whether the directory owns the user lifecycle. Manual and SCIM-managed paths both lead to organization membership and role assignment, while single sign-on separately controls how people authenticate.\n start[\"Choose how this population is managed\"] --> directory{\"Directory owns user lifecycle?\"}\n directory -->|\"No\"| manual[\"Manage users manually\"]\n directory -->|\"Yes\"| scim[\"Provision users with SCIM\"]\n manual --> roles[\"Assign roles and manage membership\"]\n roles --> access[\"Access in the selected organization\"]\n roles --> units[\"Limit access to a team, department or region when needed\"]\n sso[\"Single sign-on\"] --> signIn[\"How people authenticate\"]\n signIn --> manual\n signIn --> scim\n~~~\n\n## Choose how your organization manages users\n\n{{CONSUMER_FACT:source:consumer-fact:organization-membership-administration#markdown}}\n\nChoose **manual management** when an administrator should invite people, choose\ntheir access, pause access, or remove them directly in the application. Each\nmembership and role belongs to one organization. In plain language: giving\nsomeone access to one organization does not give them access to another.\n\nChoose **SCIM** when your company’s identity directory is responsible for\ncreating, updating and deactivating a defined group of people. Do not make the\nsame change manually and in the directory: it becomes unclear which change\nshould win.\n\n> **SSO and SCIM solve different problems.** SSO changes how a person proves\n> their identity when they sign in. SCIM can manage a directory-owned user\n> lifecycle. Neither is an organization role, and neither should be used as a\n> shortcut around an access decision.\n\n## Choose the task you need to complete\n\n| You need to… | Start here | What you will do |\n| --- | --- | --- |\n| Invite a colleague and help them start | [Invite and onboard a user](/user-administration/invite-and-onboard-user) | Send the invitation, follow its status, and verify access after acceptance |\n| Understand the access levels available in this application | [Roles and permissions](/user-administration/roles-and-permissions) | Compare every organization role, what it allows, and where its authority stops |\n| Give someone more, less, or different access | [Change a user's access](/user-administration/change-user-access) | Review their current organization, roles and any unit-level assignment before changing them |\n| Structure access by team, department, region, or another business area | [Manage organization units](/user-administration/manage-organization-units) | Build a hierarchy, choose inheritance, and assign people to the units where they work |\n| Put access on hold or end it | [Suspend or remove a user](/user-administration/suspend-or-remove-user) | Choose the reversible or permanent action that matches the situation |\n| Let your company directory manage a population | [Provision users with SCIM](/user-administration/scim-provisioning) | Set up and monitor directory-driven lifecycle changes |\n| Confirm who has access and whether it is still appropriate | [Review users and access](/user-administration/review-users-and-access) | Review membership states, privileged roles, unit assignments and directory ownership |\n| Find why a person cannot use the application as expected | [Troubleshoot user access](/user-administration/troubleshoot-user-access) | Start from the person’s symptom and check identity, organization, membership and role in order |\n| Let people sign in through your company identity provider | [Single sign-on](/access-and-identity/single-sign-on) | Change sign-in only; it does not take over membership or offboarding |\n\n## A short vocabulary before you begin\n\n- A **user** is a person’s application identity.\n- A **membership** is that person’s relationship with one organization. It\n records whether access is pending, active, paused or inactive.\n- A **role** is the set of actions the person is allowed to perform in that\n organization.\n- An **organization unit** is a department, team, region, or other part of one\n organization used to narrow access to unit-aware resources.\n- An **organization owner** is an administrator with responsibility for keeping\n that organization manageable. Every organization needs at least one usable\n owner.\n\nYou can work with these concepts from the user-management screens; this page\nuses the terms only so the next steps are predictable.\n\n## Keep access safe and recoverable\n\nBefore a role change, suspension or removal, identify another active owner if\nthe affected person is currently the organization’s only usable owner. A\nrefused continuity change is a safety control, not an invitation to bypass the\norganization boundary. Establish the replacement owner, verify their access,\nthen retry the intended change. For a significant access change, record why it\nwas made and use [Security and audit](/security-and-audit)\nto investigate the result later.";
107
+ readonly sourceRefs: readonly ["saas-technical-doc:engine-content/user-administration"];
108
+ readonly markdown: "# User administration\n\nManage the people who can use your organization and the access they have. Start\nwith the task in front of you: invite someone, change their access, or stop\ntheir access. Most organizations manage people directly in the application. If\nyour company uses an identity directory, it may instead keep the user list in\nsync automatically.\n\n~~~mermaid\nflowchart LR\n accTitle: Choose manual or directory-managed user administration\n accDescr: The administrator decides whether the directory owns the user lifecycle. Manual and SCIM-managed paths both lead to organization membership and role assignment, while single sign-on separately controls how people authenticate.\n start[\"Choose how this population is managed\"] --> directory{\"Directory owns user lifecycle?\"}\n directory -->|\"No\"| manual[\"Manage users manually\"]\n directory -->|\"Yes\"| scim[\"Provision users with SCIM\"]\n manual --> roles[\"Assign roles and manage membership\"]\n roles --> access[\"Access in the selected organization\"]\n roles --> units[\"Limit access to a team, department or region when needed\"]\n sso[\"Single sign-on\"] --> signIn[\"How people authenticate\"]\n signIn --> manual\n signIn --> scim\n~~~\n\n## Choose how your organization manages users\n\nMembership states, the roles available in this application and the last-owner rule are listed once, on [Roles and permissions](/user-administration/roles-and-permissions).\n\nChoose **manual management** when an administrator should invite people, choose\ntheir access, pause access, or remove them directly in the application. Each\nmembership and role belongs to one organization. In plain language: giving\nsomeone access to one organization does not give them access to another.\n\nChoose **SCIM** when your company’s identity directory is responsible for\ncreating, updating and deactivating a defined group of people. Do not make the\nsame change manually and in the directory: it becomes unclear which change\nshould win.\n\n> **SSO and SCIM solve different problems.** SSO changes how a person proves\n> their identity when they sign in. SCIM can manage a directory-owned user\n> lifecycle. Neither is an organization role, and neither should be used as a\n> shortcut around an access decision.\n\n## Choose the task you need to complete\n\n| You need to… | Start here | What you will do |\n| --- | --- | --- |\n| Invite a colleague and help them start | [Invite and onboard a user](/user-administration/invite-and-onboard-user) | Send the invitation, follow its status, and verify access after acceptance |\n| Understand the access levels available in this application | [Roles and permissions](/user-administration/roles-and-permissions) | Compare every organization role, what it allows, and where its authority stops |\n| Give someone more, less, or different access | [Change a user's access](/user-administration/change-user-access) | Review their current organization, roles and any unit-level assignment before changing them |\n| Structure access by team, department, region, or another business area | [Manage organization units](/user-administration/manage-organization-units) | Build a hierarchy, choose inheritance, and assign people to the units where they work |\n| Put access on hold or end it | [Suspend or remove a user](/user-administration/suspend-or-remove-user) | Choose the reversible or permanent action that matches the situation |\n| Let your company directory manage a population | [Provision users with SCIM](/user-administration/scim-provisioning) | Set up and monitor directory-driven lifecycle changes |\n| Confirm who has access and whether it is still appropriate | [Review users and access](/user-administration/review-users-and-access) | Review membership states, privileged roles, unit assignments and directory ownership |\n| Find why a person cannot use the application as expected | [Troubleshoot user access](/user-administration/troubleshoot-user-access) | Start from the person’s symptom and check identity, organization, membership and role in order |\n| Let people sign in through your company identity provider | [Single sign-on](/access-and-identity/single-sign-on) | Change sign-in only; it does not take over membership or offboarding |\n\n## A short vocabulary before you begin\n\n- A **user** is a person’s application identity.\n- A **membership** is that person’s relationship with one organization. It\n records whether access is pending, active, paused or inactive.\n- A **role** is the set of actions the person is allowed to perform in that\n organization.\n- An **organization unit** is a department, team, region, or other part of one\n organization used to narrow access to unit-aware resources.\n- An **organization owner** is an administrator with responsibility for keeping\n that organization manageable. Every organization needs at least one usable\n owner.\n\nYou can work with these concepts from the user-management screens; this page\nuses the terms only so the next steps are predictable.\n\n## Keep access safe and recoverable\n\nBefore a role change, suspension or removal, identify another active owner if\nthe affected person is currently the organization’s only usable owner. A\nrefused continuity change is a safety control, not an invitation to bypass the\norganization boundary. Establish the replacement owner, verify their access,\nthen retry the intended change. For a significant access change, record why it\nwas made and use [Security and audit](/security-and-audit)\nto investigate the result later.";
109
109
  }, {
110
110
  readonly managedPath: "user-administration/manage-users-manually.md";
111
111
  readonly unitRef: "technical-documentation:unit/manage-users-manually";
@@ -114,23 +114,23 @@ export declare const APPLICATION_CONSUMER_DOCUMENTATION_AUTHORED_CONTENT_V1: rea
114
114
  }, {
115
115
  readonly managedPath: "user-administration/invite-and-onboard-user.md";
116
116
  readonly unitRef: "technical-documentation:unit/invite-and-onboard-user";
117
- readonly sourceRefs: readonly ["saas-technical-doc:engine-content/invite-and-onboard-user", "source:consumer-fact:organization-membership-administration"];
118
- readonly markdown: "# Invite and onboard a user\n\nInvite a person when they need access to one organization and that organization\nis managed manually. An invitation is an access offer, not active access: the\nperson becomes active only after accepting it. This protects both the person\nand the organization from an account gaining access before the intended person\nhas completed the sign-in journey.\n\n## What you need and what success looks like\n\n| | |\n| --- | --- |\n| **Who performs this task** | An organization owner or administrator responsible for membership access |\n| **Where the change applies** | One selected organization; it does not give the person access to another organization |\n| **Before you begin** | Confirm the person’s work email, approved role, intended organization and whether SCIM owns their lifecycle |\n| **Successful result** | One member row is **Invited**, then that same row becomes **Active** after acceptance with the approved role |\n\n## Open member administration\n\n1. Select the organization the person should join.\n2. Open **Settings**, then the organization’s **Members** area.\n3. Confirm the organization shown in the member directory before entering any\n personal information.\n4. Choose the action for adding a member. The application may label this action\n **Add member** or use the application’s equivalent translated label.\n\nIf your organization automates invitations, use the invitation API operations\nlinked from this page. Each link resolves an exact operation published by this\napplication; do not construct an endpoint from this guide.\n\n> **An invitation is not active access.** It creates an **Invited** membership.\n> That membership contributes no organization authority until the intended\n> person accepts the single-use invitation and the same membership becomes\n> **Active**.\n\n~~~mermaid\nflowchart TD\n accTitle: Invite a person and activate their organization membership\n accDescr: The administrator confirms the organization and access, sends an invitation, and waits for acceptance. The pending invitation can be resent or revoked; successful acceptance activates the membership.\n need[\"Person needs access\"] --> check[\"Confirm organization and required access\"]\n check --> invite[\"Send invitation to the person's work email\"]\n invite --> pending[\"Invitation is pending\"]\n pending --> accepted{\"Person accepts?\"}\n accepted -->|\"Yes\"| active[\"Membership becomes active\"]\n accepted -->|\"No longer needed\"| revoke[\"Revoke the pending invitation\"]\n pending --> resend[\"Resend if the person did not receive it\"]\n~~~\n\n## Before you send an invitation\n\nFirst ask whether an invitation is the right path:\n\n- **Is this person managed manually?** If SCIM owns their lifecycle, provision\n them from the directory instead.\n- **Do they need access to this organization?** A person who only needs an\n integration credential should not receive a human membership as a shortcut.\n- **Is their work email the right identity anchor?** Confirm it with the person\n or their manager; do not use a shared mailbox.\n\nThen confirm all three choices with the person’s manager or access owner:\n\n1. **Organization:** choose where the person will work. A membership is\n specific to that organization.\n2. **Access:** choose the smallest role that lets the person do their job. Do\n not use an owner-level role as a shortcut for a missing permission.\n3. **Identity:** use the person’s work email and confirm that it belongs to the\n intended person. Do not reuse a colleague’s address or a shared mailbox.\n\n## Send and follow the invitation\n\n{{CONSUMER_FACT:source:consumer-fact:organization-membership-administration#markdown}}\n\nAfter you send it, find the person in the member list and check that the state\nis **Invited**. At this point, the person has not received active organization\nauthority. If they cannot find the email, first confirm the address and their\nemail filtering rules, then use the published resend action for the pending\ninvitation. Resending replaces the earlier acceptance link; do not create a\nsecond invitation for the same person just to send another email.\n\nThe invitation link is valid for **seven days** and can be used once. If the\nlink is expired, revoked, already consumed, or no longer matches an invited\nmembership, the acceptance must fail rather than activating a different state.\n\nIf the access offer is no longer appropriate, revoke the pending invitation.\nDo not activate the membership yourself to work around an acceptance problem:\nacceptance is the step that confirms the recipient is taking up that access.\n\n## Confirm the first day of access\n\nAfter the person accepts, confirm that their membership is **Active**, they are\nin the intended organization, and their role is the one you approved. In an\norganization that manages users manually, single sign-on verifies the person’s\nidentity; the membership and roles you assigned determine their access.\n\nIf the person needs a different role after joining, use [Change a user's\naccess](/user-administration/change-user-access). If they should no longer\nhave access, choose [Suspend or remove a user](/user-administration/suspend-or-remove-user)\nrather than leaving an unwanted active membership.\n\n### Can single sign-on complete the invitation?\n\nYes. When the configured federated sign-in identifies the same person as a\npending invitation, their first successful identity-provider sign-in can\nconsume that invitation and activate the existing membership. The membership\nand the roles chosen when the invitation was created still determine the access\nthey receive; SSO does not invent or widen those roles.\n\nIf the configured sign-in journey does not consume the invitation, the person\nmust follow the application’s published acceptance path. In either case,\nconfirm that the original **Invited** membership became **Active** rather than\ncreating a second membership.\n\n### Should you create another invitation when the email is lost?\n\nNo. Confirm the address, then resend the existing pending invitation. Creating\nduplicates makes it harder to know which access offer and role set should win.\n\n### When should you revoke an invitation?\n\nRevoke it when the person should no longer join, the address is wrong, or the\napproved role or organization has changed materially. Create a new, reviewed\noffer when the underlying access decision changes.";
117
+ readonly sourceRefs: readonly ["saas-technical-doc:engine-content/invite-and-onboard-user"];
118
+ readonly markdown: "# Invite and onboard a user\n\nInvite a person when they need access to one organization and that organization\nis managed manually. An invitation is an access offer, not active access: the\nperson becomes active only after accepting it. This protects both the person\nand the organization from an account gaining access before the intended person\nhas completed the sign-in journey.\n\n## What you need and what success looks like\n\n| | |\n| --- | --- |\n| **Who performs this task** | An organization owner or administrator responsible for membership access |\n| **Where the change applies** | One selected organization; it does not give the person access to another organization |\n| **Before you begin** | Confirm the person’s work email, approved role, intended organization and whether SCIM owns their lifecycle |\n| **Successful result** | One member row is **Invited**, then that same row becomes **Active** after acceptance with the approved role |\n\n## Open member administration\n\n1. Select the organization the person should join.\n2. Open **Settings**, then the organization’s **Members** area.\n3. Confirm the organization shown in the member directory before entering any\n personal information.\n4. Choose the action for adding a member. The application may label this action\n **Add member** or use the application’s equivalent translated label.\n\nIf your organization automates invitations, use the invitation API operations\nlinked from this page. Each link resolves an exact operation published by this\napplication; do not construct an endpoint from this guide.\n\n> **An invitation is not active access.** It creates an **Invited** membership.\n> That membership contributes no organization authority until the intended\n> person accepts the single-use invitation and the same membership becomes\n> **Active**.\n\n~~~mermaid\nflowchart TD\n accTitle: Invite a person and activate their organization membership\n accDescr: The administrator confirms the organization and access, sends an invitation, and waits for acceptance. The pending invitation can be resent or revoked; successful acceptance activates the membership.\n need[\"Person needs access\"] --> check[\"Confirm organization and required access\"]\n check --> invite[\"Send invitation to the person's work email\"]\n invite --> pending[\"Invitation is pending\"]\n pending --> accepted{\"Person accepts?\"}\n accepted -->|\"Yes\"| active[\"Membership becomes active\"]\n accepted -->|\"No longer needed\"| revoke[\"Revoke the pending invitation\"]\n pending --> resend[\"Resend if the person did not receive it\"]\n~~~\n\n## Before you send an invitation\n\nFirst ask whether an invitation is the right path:\n\n- **Is this person managed manually?** If SCIM owns their lifecycle, provision\n them from the directory instead.\n- **Do they need access to this organization?** A person who only needs an\n integration credential should not receive a human membership as a shortcut.\n- **Is their work email the right identity anchor?** Confirm it with the person\n or their manager; do not use a shared mailbox.\n\nThen confirm all three choices with the person’s manager or access owner:\n\n1. **Organization:** choose where the person will work. A membership is\n specific to that organization.\n2. **Access:** choose the smallest role that lets the person do their job. Do\n not use an owner-level role as a shortcut for a missing permission.\n3. **Identity:** use the person’s work email and confirm that it belongs to the\n intended person. Do not reuse a colleague’s address or a shared mailbox.\n\n## Send and follow the invitation\n\nMembership states, the roles available in this application and the last-owner rule are listed once, on [Roles and permissions](/user-administration/roles-and-permissions).\n\nAfter you send it, find the person in the member list and check that the state\nis **Invited**. At this point, the person has not received active organization\nauthority. If they cannot find the email, first confirm the address and their\nemail filtering rules, then use the published resend action for the pending\ninvitation. Resending replaces the earlier acceptance link; do not create a\nsecond invitation for the same person just to send another email.\n\nThe invitation link is valid for **seven days** and can be used once; resend\nit to issue a fresh link. An invitation that is neither accepted nor revoked\nis removed automatically after **30 days**, so a person who never responds\ndoes not stay listed as invited indefinitely. If the\nlink is expired, revoked, already consumed, or no longer matches an invited\nmembership, the acceptance must fail rather than activating a different state.\n\nIf the access offer is no longer appropriate, revoke the pending invitation.\nDo not activate the membership yourself to work around an acceptance problem:\nacceptance is the step that confirms the recipient is taking up that access.\n\n## Confirm the first day of access\n\nAfter the person accepts, confirm that their membership is **Active**, they are\nin the intended organization, and their role is the one you approved. In an\norganization that manages users manually, single sign-on verifies the person’s\nidentity; the membership and roles you assigned determine their access.\n\nIf the person needs a different role after joining, use [Change a user's\naccess](/user-administration/change-user-access). If they should no longer\nhave access, choose [Suspend or remove a user](/user-administration/suspend-or-remove-user)\nrather than leaving an unwanted active membership.\n\n### Can single sign-on complete the invitation?\n\nYes. When the configured federated sign-in identifies the same person as a\npending invitation, their first successful identity-provider sign-in can\nconsume that invitation and activate the existing membership. The membership\nand the roles chosen when the invitation was created still determine the access\nthey receive; SSO does not invent or widen those roles.\n\nIf the configured sign-in journey does not consume the invitation, the person\nmust follow the application’s published acceptance path. In either case,\nconfirm that the original **Invited** membership became **Active** rather than\ncreating a second membership.\n\n### Should you create another invitation when the email is lost?\n\nNo. Confirm the address, then resend the existing pending invitation. Creating\nduplicates makes it harder to know which access offer and role set should win.\n\n### When should you revoke an invitation?\n\nRevoke it when the person should no longer join, the address is wrong, or the\napproved role or organization has changed materially. Create a new, reviewed\noffer when the underlying access decision changes.";
119
119
  }, {
120
120
  readonly managedPath: "user-administration/roles-and-permissions.md";
121
121
  readonly unitRef: "technical-documentation:unit/organization-roles";
122
- readonly sourceRefs: readonly ["saas-technical-doc:engine-content/organization-roles", "source:companion-projection:organization-roles", "source:consumer-fact:organization-membership-administration"];
123
- readonly markdown: "# Roles and permissions\n\nRoles describe what a person may do in an organization. Use this page before\nyou invite someone or change their access: it lists the roles that are actually\navailable in this application, including roles added specifically for this\napplication.\n\n> **Choose access for the work, not for the person’s job title.** Start with\n> the task they need to complete, decide where that authority must apply, then\n> choose the least privileged role that is sufficient.\n\n~~~mermaid\nflowchart TD\n accTitle: Choose organization-wide or unit-specific access\n accDescr: Start from the work a person must perform, choose where that authority applies, compare the available role or unit rules, and verify both allowed and refused actions.\n need[\"Describe the work the person must perform\"] --> scope{\"Where must the authority apply?\"}\n scope -->|\"Across the organization\"| organizationRole[\"Choose an organization role\"]\n scope -->|\"One team, department or region\"| unitRole[\"Choose an organization unit and a unit role\"]\n organizationRole --> compare[\"Compare the available roles below\"]\n unitRole --> unitGuide[\"Review organization-unit inheritance\"]\n compare --> verify[\"Verify the approved task with the person's own account\"]\n unitGuide --> verify\n verify --> boundary[\"Confirm a nearby unapproved task is still refused\"]\n~~~\n\n## How organization roles work\n\n{{CONSUMER_FACT:source:consumer-fact:organization-membership-administration#markdown}}\n\nA role belongs to a person’s membership in **one organization**. It does not\nfollow them into another organization, and it contributes no authority while\nthat membership is not **Active**.\n\nSome roles include another role. That means the higher role receives the\npermissions of the included role as well as its own permissions. Inclusion\nworks upward through the role hierarchy; assigning the lower role never grants\nthe higher role’s authority.\n\nThe role descriptions below explain their intended use and boundary. A\nspecific operation may impose a narrower rule, so the API reference remains\nauthoritative when you need to know exactly who may call one operation.\n\n## Roles available in this application\n\n{{APPLICATION_ORGANIZATION_ROLES}}\n\n## How to choose a role\n\nBefore assigning a role, answer these questions:\n\n1. **What must the person be able to do?** Name the concrete task or decision,\n not a vague request for “more access.”\n2. **Must it apply across the organization?** If the work is limited to a\n department, team, region, or another business area, use an organization-unit\n assignment when the relevant resources support it.\n3. **Does an existing role already cover the need?** Prefer that role to a\n broader one. A permission error is not, by itself, a reason to grant\n administrator or owner access.\n4. **Who approved the change?** Keep the business reason and accountable\n approver with the access-change record.\n5. **How will you verify least privilege?** Test the approved task with the\n person’s own account, then confirm that a nearby unapproved task is still\n refused.\n\n## Organization roles and unit roles are different\n\nAn **organization role** may authorize work throughout the organization. An\n**organization-unit role** is a separate grant for one unit and, when\nconfigured, its descendants. A unit role grants nothing on resources that do\nnot support organization-unit narrowing, and it does not replace the person’s\norganization role.\n\nRead [Manage organization units](/user-administration/manage-organization-units)\nbefore assigning access at a parent or root unit. The unit’s inheritance setting\ncan make the same assignment effective in several descendant units.\n\n## Protect owner continuity\n\nAn organization must retain a usable owner. The application refuses a role\nreduction, suspension, or removal that would leave no active owner able to\nadminister the organization. Establish another owner, verify that person can\nadminister the organization, then retry the original change.\n\n## Apply and verify a role change\n\nUse [Change a user's access](/user-administration/change-user-access) for the\nstep-by-step decision and verification process. After the change:\n\n- confirm the intended organization, active membership, organization roles,\n and any unit assignments;\n- ask the person to perform the approved task with **their own account**;\n- confirm an adjacent task they were not granted is still refused; and\n- review the audit record for the actor, affected person, organization, change,\n and outcome.\n\n### Does single sign-on assign a role?\n\nNo. Single sign-on proves who the person is. Their organization membership and\nroles determine what they may do after sign-in. A SCIM connection can create a\nmembership with configured defaults, but that is a provisioning decision, not\nan SSO decision.\n\n### Can an administrator grant any role?\n\nNo. A person cannot grant authority above their own effective organization\nrole. In particular, an organization administrator does not inherit the owner\nrole, so an effective owner must approve and perform an owner-level grant. A\nunit role never raises this organization-wide role-grant ceiling.\n\n### Why was an owner change refused?\n\nThe requested change may have left the organization without an active, usable\nowner. Establish and verify replacement owner coverage first; do not try a\ndifferent credential to bypass the refusal.";
122
+ readonly sourceRefs: readonly ["saas-technical-doc:engine-content/organization-roles", "source:companion-projection:application-administration", "source:companion-projection:organization-roles", "source:consumer-fact:organization-membership-administration"];
123
+ readonly markdown: "# Roles and permissions\n\nRoles describe what a person may do in an organization. Use this page before\nyou invite someone or change their access: it lists the roles that are actually\navailable in this application, including roles added specifically for this\napplication.\n\n> **Choose access for the work, not for the person’s job title.** Start with\n> the task they need to complete, decide where that authority must apply, then\n> choose the least privileged role that is sufficient.\n\n~~~mermaid\nflowchart TD\n accTitle: Choose organization-wide or unit-specific access\n accDescr: Start from the work a person must perform, choose where that authority applies, compare the available role or unit rules, and verify both allowed and refused actions.\n need[\"Describe the work the person must perform\"] --> scope{\"Where must the authority apply?\"}\n scope -->|\"Across the organization\"| organizationRole[\"Choose an organization role\"]\n scope -->|\"One team, department or region\"| unitRole[\"Choose an organization unit and a unit role\"]\n organizationRole --> compare[\"Compare the available roles below\"]\n unitRole --> unitGuide[\"Review organization-unit inheritance\"]\n compare --> verify[\"Verify the approved task with the person's own account\"]\n unitGuide --> verify\n verify --> boundary[\"Confirm a nearby unapproved task is still refused\"]\n~~~\n\n## How organization roles work\n\n{{CONSUMER_FACT:source:consumer-fact:organization-membership-administration#markdown}}\n\nA role belongs to a person’s membership in **one organization**. It does not\nfollow them into another organization, and it contributes no authority while\nthat membership is not **Active**.\n\nSome roles include another role. That means the higher role receives the\npermissions of the included role as well as its own permissions. Inclusion\nworks upward through the role hierarchy; assigning the lower role never grants\nthe higher role’s authority.\n\nThe role descriptions below explain their intended use and boundary. A\nspecific operation may impose a narrower rule, so the API reference remains\nauthoritative when you need to know exactly who may call one operation.\n\n## Who may administer membership here\n\nThe roles above say what each role is for. This says which of them may perform\neach membership action this application publishes:\n\n{{APPLICATION_ADMINISTRATION:memberActions}}\n\n## Roles available in this application\n\n{{APPLICATION_ORGANIZATION_ROLES}}\n\n## How to choose a role\n\nBefore assigning a role, answer these questions:\n\n1. **What must the person be able to do?** Name the concrete task or decision,\n not a vague request for “more access.”\n2. **Must it apply across the organization?** If the work is limited to a\n department, team, region, or another business area, use an organization-unit\n assignment when the relevant resources support it.\n3. **Does an existing role already cover the need?** Prefer that role to a\n broader one. A permission error is not, by itself, a reason to grant\n administrator or owner access.\n4. **Who approved the change?** Keep the business reason and accountable\n approver with the access-change record.\n5. **How will you verify least privilege?** Test the approved task with the\n person’s own account, then confirm that a nearby unapproved task is still\n refused.\n\n## Organization roles and unit roles are different\n\nAn **organization role** may authorize work throughout the organization. An\n**organization-unit role** is a separate grant for one unit and, when\nconfigured, its descendants. A unit role grants nothing on resources that do\nnot support organization-unit narrowing, and it does not replace the person’s\norganization role.\n\nRead [Manage organization units](/user-administration/manage-organization-units)\nbefore assigning access at a parent or root unit. The unit’s inheritance setting\ncan make the same assignment effective in several descendant units.\n\n## Protect owner continuity\n\nAn organization must retain a usable owner. The application refuses a role\nreduction, suspension, or removal that would leave no active owner able to\nadminister the organization. Establish another owner, verify that person can\nadminister the organization, then retry the original change.\n\n## Apply and verify a role change\n\nUse [Change a user's access](/user-administration/change-user-access) for the\nstep-by-step decision and verification process. After the change:\n\n- confirm the intended organization, active membership, organization roles,\n and any unit assignments;\n- ask the person to perform the approved task with **their own account**;\n- confirm an adjacent task they were not granted is still refused; and\n- review the audit record for the actor, affected person, organization, change,\n and outcome.\n\n### Does single sign-on assign a role?\n\nNo. Single sign-on proves who the person is. Their organization membership and\nroles determine what they may do after sign-in. A SCIM connection can create a\nmembership with configured defaults, but that is a provisioning decision, not\nan SSO decision.\n\n### Can an administrator grant any role?\n\nNo. A person cannot grant authority above their own effective organization\nrole. In particular, an organization administrator does not inherit the owner\nrole, so an effective owner must approve and perform an owner-level grant. A\nunit role never raises this organization-wide role-grant ceiling.\n\n### Why was an owner change refused?\n\nThe requested change may have left the organization without an active, usable\nowner. Establish and verify replacement owner coverage first; do not try a\ndifferent credential to bypass the refusal.";
124
124
  }, {
125
125
  readonly managedPath: "user-administration/change-user-access.md";
126
126
  readonly unitRef: "technical-documentation:unit/change-user-access";
127
- readonly sourceRefs: readonly ["saas-technical-doc:engine-content/change-user-access", "source:consumer-fact:organization-membership-administration"];
128
- readonly markdown: "# Change a user's access\n\nChange access when a person’s responsibilities change. **Do not assign a broad\nrole simply to make an error disappear.** First identify the work the person\nmust perform, then decide whether that authority belongs across the organization\nor only inside a department, team, region, or other organization unit.\n\n## What you need and what success looks like\n\n| | |\n| --- | --- |\n| **Who performs this task** | An organization owner or administrator whose own authority permits the requested role |\n| **Where the change applies** | The person’s membership in one selected organization, plus any explicitly selected unit assignments |\n| **Before you begin** | Obtain the approved responsibility, current roles, current unit assignments and a named approver for privileged access |\n| **Successful result** | The membership shows the intended least-privileged role and scope, the approved task succeeds, and a nearby unapproved task remains refused |\n\n## Open the person’s membership\n\n1. Select the intended organization.\n2. Open **Settings**, then **Members** in the organization area.\n3. Find the person by their own identity rather than by a colleague’s account\n or a shared mailbox.\n4. Open the member details and choose the application’s update action.\n5. Review the current **Roles**, **Status** and **Unit membership** values before\n changing any one of them.\n\nFor automated changes, follow the membership API operations linked from this\npage. They remain the authority for the exact request, role gate and response\nproduced by this application.\n\n> **Start with scope, then choose a role.** An organization role can apply\n> throughout the organization. A unit assignment limits a role to unit-aware\n> resources in one part of the organization. Choosing the role before choosing\n> the scope is a common way to grant too much access.\n\n## What are you trying to change?\n\n| The person needs… | Use | Do not use |\n| --- | --- | --- |\n| Permission throughout the organization | An organization role | A root-unit assignment as a disguised organization-wide grant |\n| Permission only in a team, department, region, or project group | A unit assignment and unit role | A broader organization role |\n| A temporary loss of all organization access | Suspend the membership | A collection of role removals that will be difficult to restore |\n| A permanent end to this organization relationship | Remove the membership | A low role that leaves unwanted access active |\n\n~~~mermaid\nflowchart TD\n accTitle: Change a person's access without breaking owner continuity\n accDescr: The administrator decides whether the person remains active, chooses organization-wide or unit-scoped authority, protects the last usable owner, and verifies the resulting access and audit evidence.\n request[\"A person's responsibilities change\"] --> active{\"Should the person remain an active member?\"}\n active -->|\"No, temporarily\"| suspend[\"Suspend the membership\"]\n active -->|\"No, permanently\"| remove[\"Remove the membership\"]\n active -->|\"Yes\"| scope{\"Where must the authority apply?\"}\n scope -->|\"Across the organization\"| orgRole[\"Choose an organization role\"]\n scope -->|\"One business area\"| unitRole[\"Choose a unit and unit role\"]\n orgRole --> continuity{\"Would this remove the last usable owner?\"}\n unitRole --> verify[\"Verify with the person's own account\"]\n continuity -->|\"Yes\"| replacement[\"Establish and verify a replacement owner first\"]\n continuity -->|\"No\"| verify\n replacement --> verify\n verify --> evidence[\"Review the resulting state and audit record\"]\n~~~\n\n## Questions to answer before you make the change\n\n- **Which organization is affected?** Roles do not follow a person from one\n organization to another.\n- **What specific task or responsibility requires access?** Use a business\n outcome, not a vague request for “more access.”\n- **Must the authority apply everywhere, or only in one unit?** Review existing\n unit assignments as well as organization roles.\n- **Is the change temporary?** A suspension may express the real intent more\n clearly than editing several roles.\n- **Who approved a privileged change?** Record the business reason and the\n person accountable for the decision.\n\n## How membership state affects authority\n\n{{CONSUMER_FACT:source:consumer-fact:organization-membership-administration#markdown}}\n\nOnly an **Active** membership contributes organization authority. A role is not\na job title: it is a named permission set evaluated in the selected\norganization. The exact operation contract remains authoritative when a role\ndescription and a specific API operation need to be compared.\n\n## Which organization role should you choose?\n\nUse [Roles and permissions](/user-administration/roles-and-permissions) to\ncompare the complete role set available in this application, including any\napplication-specific roles. Choose the least privileged role that covers the\nperson’s approved responsibility, then return here to verify the change.\n\n> **A role name is not enough evidence.** The application evaluates the roles\n> accepted by each operation. Use the API reference for an exact endpoint and\n> use the resulting access check with the person’s own account to verify the\n> practical outcome.\n\n## How is unit-specific access different?\n\nA unit role is a separate, narrowed grant. It can authorize only resources that\nexplicitly support organization-unit narrowing. It does not replace the\nperson’s organization role, and it grants nothing on resources that are not\nunit-aware. A person can hold one role per unit, and a unit can optionally pass\nthat role down to its descendants.\n\nUse [Manage organization units](/user-administration/manage-organization-units)\nto understand hierarchy and inheritance before granting a role at a parent or\nroot unit.\n\n## What if the person is the last organization owner?\n\nThe application refuses a suspension, removal, or role reduction that would\nleave the organization without a usable owner. This is an administrative\ncontinuity control. Make another **Active** member an owner, verify that the\nreplacement can administer the organization, and only then retry the original\nchange.\n\n## How do you verify the result?\n\n1. Re-open the person’s membership and confirm the intended organization,\n membership state, organization role set, and unit assignments.\n2. Ask the person to use **their own account** in the intended organization and\n perform the approved task. Do not test with an administrator’s session.\n3. Confirm that a nearby unapproved task is still refused; successful access\n alone does not prove least privilege.\n4. Review the audit record for the actor, affected person, organization,\n before-and-after role evidence, and outcome.\n\n### Does SSO assign the person’s role?\n\nNo. SSO proves identity during sign-in. In a manually managed organization,\nthe membership and role assignment still decide application access. A SCIM\nconnection can create a membership with configured defaults, but that is a\nprovisioning decision, not an SSO decision.\n\n### Does a unit role replace the organization role?\n\nNo. The two grants coexist and are evaluated for different scopes. Removing a\nunit assignment does not remove organization-wide roles, and reducing an\norganization role does not automatically remove unit assignments.\n\n### Can an organization administrator make someone an owner?\n\nNo. A person can grant only roles included by their own organization-wide\nauthority. **Organization administrator** does not include **Organization\nowner**, so an effective owner must approve and perform an owner-level grant.\nA unit role never raises this role-grant ceiling.\n\n### Why was an owner change refused?\n\nMost often, the requested change would leave no active, administratively usable\nowner. Establish replacement owner coverage first. Do not try a more powerful\ncredential to bypass the refusal.";
127
+ readonly sourceRefs: readonly ["saas-technical-doc:engine-content/change-user-access"];
128
+ readonly markdown: "# Change a user's access\n\nChange access when a person’s responsibilities change. **Do not assign a broad\nrole simply to make an error disappear.** First identify the work the person\nmust perform, then decide whether that authority belongs across the organization\nor only inside a department, team, region, or other organization unit.\n\n## What you need and what success looks like\n\n| | |\n| --- | --- |\n| **Who performs this task** | An organization owner or administrator whose own authority permits the requested role |\n| **Where the change applies** | The person’s membership in one selected organization, plus any explicitly selected unit assignments |\n| **Before you begin** | Obtain the approved responsibility, current roles, current unit assignments and a named approver for privileged access |\n| **Successful result** | The membership shows the intended least-privileged role and scope, the approved task succeeds, and a nearby unapproved task remains refused |\n\n## Open the person’s membership\n\n1. Select the intended organization.\n2. Open **Settings**, then **Members** in the organization area.\n3. Find the person by their own identity rather than by a colleague’s account\n or a shared mailbox.\n4. Open the member details and choose the application’s update action.\n5. Review the current **Roles**, **Status** and **Unit membership** values before\n changing any one of them.\n\nFor automated changes, follow the membership API operations linked from this\npage. They remain the authority for the exact request, role gate and response\nproduced by this application.\n\n> **Start with scope, then choose a role.** An organization role can apply\n> throughout the organization. A unit assignment limits a role to unit-aware\n> resources in one part of the organization. Choosing the role before choosing\n> the scope is a common way to grant too much access.\n\n## What are you trying to change?\n\n| The person needs… | Use | Do not use |\n| --- | --- | --- |\n| Permission throughout the organization | An organization role | A root-unit assignment as a disguised organization-wide grant |\n| Permission only in a team, department, region, or project group | A unit assignment and unit role | A broader organization role |\n| A temporary loss of all organization access | Suspend the membership | A collection of role removals that will be difficult to restore |\n| A permanent end to this organization relationship | Remove the membership | A low role that leaves unwanted access active |\n\n~~~mermaid\nflowchart TD\n accTitle: Change a person's access without breaking owner continuity\n accDescr: The administrator decides whether the person remains active, chooses organization-wide or unit-scoped authority, protects the last usable owner, and verifies the resulting access and audit evidence.\n request[\"A person's responsibilities change\"] --> active{\"Should the person remain an active member?\"}\n active -->|\"No, temporarily\"| suspend[\"Suspend the membership\"]\n active -->|\"No, permanently\"| remove[\"Remove the membership\"]\n active -->|\"Yes\"| scope{\"Where must the authority apply?\"}\n scope -->|\"Across the organization\"| orgRole[\"Choose an organization role\"]\n scope -->|\"One business area\"| unitRole[\"Choose a unit and unit role\"]\n orgRole --> continuity{\"Would this remove the last usable owner?\"}\n unitRole --> verify[\"Verify with the person's own account\"]\n continuity -->|\"Yes\"| replacement[\"Establish and verify a replacement owner first\"]\n continuity -->|\"No\"| verify\n replacement --> verify\n verify --> evidence[\"Review the resulting state and audit record\"]\n~~~\n\n## Questions to answer before you make the change\n\n- **Which organization is affected?** Roles do not follow a person from one\n organization to another.\n- **What specific task or responsibility requires access?** Use a business\n outcome, not a vague request for “more access.”\n- **Must the authority apply everywhere, or only in one unit?** Review existing\n unit assignments as well as organization roles.\n- **Is the change temporary?** A suspension may express the real intent more\n clearly than editing several roles.\n- **Who approved a privileged change?** Record the business reason and the\n person accountable for the decision.\n\n## How membership state affects authority\n\nMembership states, the roles available in this application and the last-owner rule are listed once, on [Roles and permissions](/user-administration/roles-and-permissions).\n\nOnly an **Active** membership contributes organization authority. A role is not\na job title: it is a named permission set evaluated in the selected\norganization. The exact operation contract remains authoritative when a role\ndescription and a specific API operation need to be compared.\n\n## Which organization role should you choose?\n\nUse [Roles and permissions](/user-administration/roles-and-permissions) to\ncompare the complete role set available in this application, including any\napplication-specific roles. Choose the least privileged role that covers the\nperson’s approved responsibility, then return here to verify the change.\n\n> **A role name is not enough evidence.** The application evaluates the roles\n> accepted by each operation. Use the API reference for an exact endpoint and\n> use the resulting access check with the person’s own account to verify the\n> practical outcome.\n\n## How is unit-specific access different?\n\nA unit role is a separate, narrowed grant. It can authorize only resources that\nexplicitly support organization-unit narrowing. It does not replace the\nperson’s organization role, and it grants nothing on resources that are not\nunit-aware. A person can hold one role per unit, and a unit can optionally pass\nthat role down to its descendants.\n\nUse [Manage organization units](/user-administration/manage-organization-units)\nto understand hierarchy and inheritance before granting a role at a parent or\nroot unit.\n\n## What if the person is the last organization owner?\n\nThe application refuses a suspension, removal, or role reduction that would\nleave the organization without a usable owner. This is an administrative\ncontinuity control. Make another **Active** member an owner, verify that the\nreplacement can administer the organization, and only then retry the original\nchange.\n\n## How do you verify the result?\n\n1. Re-open the person’s membership and confirm the intended organization,\n membership state, organization role set, and unit assignments.\n2. Ask the person to use **their own account** in the intended organization and\n perform the approved task. Do not test with an administrator’s session.\n3. Confirm that a nearby unapproved task is still refused; successful access\n alone does not prove least privilege.\n4. Review the audit record for the actor, affected person, organization,\n before-and-after role evidence, and outcome.\n\n### Does SSO assign the person’s role?\n\nNo. SSO proves identity during sign-in. In a manually managed organization,\nthe membership and role assignment still decide application access. A SCIM\nconnection can create a membership with configured defaults, but that is a\nprovisioning decision, not an SSO decision.\n\n### Does a unit role replace the organization role?\n\nNo. The two grants coexist and are evaluated for different scopes. Removing a\nunit assignment does not remove organization-wide roles, and reducing an\norganization role does not automatically remove unit assignments.\n\n### Can an organization administrator make someone an owner?\n\nNo. A person can grant only roles included by their own organization-wide\nauthority. **Organization administrator** does not include **Organization\nowner**, so an effective owner must approve and perform an owner-level grant.\nA unit role never raises this role-grant ceiling.\n\n### Why was an owner change refused?\n\nMost often, the requested change would leave no active, administratively usable\nowner. Establish replacement owner coverage first. Do not try a more powerful\ncredential to bypass the refusal.";
129
129
  }, {
130
130
  readonly managedPath: "user-administration/manage-organization-units.md";
131
131
  readonly unitRef: "technical-documentation:unit/manage-organization-units";
132
- readonly sourceRefs: readonly ["saas-technical-doc:engine-content/manage-organization-units", "source:companion-projection:organization-unit-aware-resources", "source:consumer-fact:organization-units"];
133
- readonly markdown: "# Manage organization units\n\nOrganization units let you mirror the parts of your organization that need\nseparately scoped access—for example departments, regions or teams. They are\nuseful only when the application has information whose access can be narrowed\nby that structure. A unit does not create another organization and does not\nreplace a person’s organization membership.\n\nAn application may present organization-unit administration in its user or\norganization settings. If it does not, use the **Organization units API\nreference** linked from this page. This guide explains the business decisions;\nthe reference supplies the exact operations the application publishes.\n\n> **Start with the business decision.** Name the information or action that a\n> department must control before you build the hierarchy. If nothing in the\n> application is unit-aware, a unit is only a label and grants no useful access.\n\n~~~mermaid\nflowchart LR\n accTitle: Decide how to use organization units\n accDescr: First design a durable hierarchy, then assign people, then verify access on a resource that the application explicitly narrows by unit.\n need[\"A business area needs separate access\"] --> design[\"Design the hierarchy\"]\n design --> assign[\"Assign members and roles\"]\n assign --> verify[\"Verify a unit-aware resource\"]\n verify --> operate[\"Review moves, archives and directory changes\"]\n~~~\n\nThe sequence matters: **structure first, assignments second, verification\nthird**. A role attached to a badly designed parent can reach more descendants\nthan intended, while a correct assignment has no effect on a resource that the\napplication does not narrow by unit.\n\n## Choose the task you need\n\n| Your goal | Continue with |\n| --- | --- |\n| Decide which departments, teams or regions belong in the hierarchy | [Design the organization-unit hierarchy](/user-administration/design-organization-unit-hierarchy) |\n| Give a person access in one part of the organization | [Assign organization-unit access](/user-administration/assign-organization-unit-access) |\n| Move, archive, restore or remove an existing unit safely | [Operate the organization-unit hierarchy](/user-administration/operate-organization-units) |\n| Let an identity directory maintain unit assignments | [Map directory data with SCIM](/user-administration/scim-map-profile-and-units) |\n\n{{CONSUMER_FACT:source:consumer-fact:organization-units#markdown}}\n\n## Information this application narrows by unit\n\n{{APPLICATION_ORGANIZATION_UNIT_RESOURCES}}\n\n## Before you begin\n\n- Confirm that the person is already an **Active** member of this organization.\n- Identify the application information that is explicitly unit-aware.\n- Choose an administrator whose organization-wide role is allowed to grant the\n intended unit role.\n- Decide whether a directory or an application administrator owns the\n assignment. Do not let both manage the same relationship.\n\n### Can a unit role make someone an organization administrator?\n\nNo. Unit access is deliberately separate from organization-wide authority. It\ncannot administer memberships, units, role assignments, organization API keys\nor other authority-bearing resources, and it never raises the administrator’s\nrole-assignment ceiling.";
132
+ readonly sourceRefs: readonly ["saas-technical-doc:engine-content/manage-organization-units", "source:companion-projection:application-administration", "source:companion-projection:organization-unit-aware-resources", "source:consumer-fact:organization-units"];
133
+ readonly markdown: "# Manage organization units\n\nOrganization units let you mirror the parts of your organization that need\nseparately scoped access—for example departments, regions or teams. They are\nuseful only when the application has information whose access can be narrowed\nby that structure. A unit does not create another organization and does not\nreplace a person’s organization membership.\n\nAn application may present organization-unit administration in its user or\norganization settings. If it does not, use the **Organization units API\nreference** linked from this page. This guide explains the business decisions;\nthe reference supplies the exact operations the application publishes.\n\n## Who may administer organization units here\n\n{{APPLICATION_ADMINISTRATION:organizationUnitActions}}\n\n> **Start with the business decision.** Name the information or action that a\n> department must control before you build the hierarchy. If nothing in the\n> application is unit-aware, a unit is only a label and grants no useful access.\n\n~~~mermaid\nflowchart LR\n accTitle: Decide how to use organization units\n accDescr: First design a durable hierarchy, then assign people, then verify access on a resource that the application explicitly narrows by unit.\n need[\"A business area needs separate access\"] --> design[\"Design the hierarchy\"]\n design --> assign[\"Assign members and roles\"]\n assign --> verify[\"Verify a unit-aware resource\"]\n verify --> operate[\"Review moves, archives and directory changes\"]\n~~~\n\nThe sequence matters: **structure first, assignments second, verification\nthird**. A role attached to a badly designed parent can reach more descendants\nthan intended, while a correct assignment has no effect on a resource that the\napplication does not narrow by unit.\n\n## Choose the task you need\n\n| Your goal | Continue with |\n| --- | --- |\n| Decide which departments, teams or regions belong in the hierarchy | [Design the organization-unit hierarchy](/user-administration/design-organization-unit-hierarchy) |\n| Give a person access in one part of the organization | [Assign organization-unit access](/user-administration/assign-organization-unit-access) |\n| Move, archive, restore or remove an existing unit safely | [Operate the organization-unit hierarchy](/user-administration/operate-organization-units) |\n| Let an identity directory maintain unit assignments | [Map directory data with SCIM](/user-administration/scim-map-profile-and-units) |\n\n{{CONSUMER_FACT:source:consumer-fact:organization-units#markdown}}\n\n## Information this application narrows by unit\n\n{{APPLICATION_ORGANIZATION_UNIT_RESOURCES}}\n\n## Before you begin\n\n- Confirm that the person is already an **Active** member of this organization.\n- Identify the application information that is explicitly unit-aware.\n- Choose an administrator whose organization-wide role is allowed to grant the\n intended unit role.\n- Decide whether a directory or an application administrator owns the\n assignment. Do not let both manage the same relationship.\n\n### Can a unit role make someone an organization administrator?\n\nNo. Unit access is deliberately separate from organization-wide authority. It\ncannot administer memberships, units, role assignments, organization API keys\nor other authority-bearing resources, and it never raises the administrator’s\nrole-assignment ceiling.";
134
134
  }, {
135
135
  readonly managedPath: "user-administration/design-organization-unit-hierarchy.md";
136
136
  readonly unitRef: "technical-documentation:unit/design-organization-unit-hierarchy";
@@ -149,13 +149,13 @@ export declare const APPLICATION_CONSUMER_DOCUMENTATION_AUTHORED_CONTENT_V1: rea
149
149
  }, {
150
150
  readonly managedPath: "user-administration/suspend-or-remove-user.md";
151
151
  readonly unitRef: "technical-documentation:unit/suspend-or-remove-user";
152
- readonly sourceRefs: readonly ["saas-technical-doc:engine-content/suspend-or-remove-user", "source:consumer-fact:organization-membership-administration"];
153
- readonly markdown: "# Suspend or remove a user\n\nWhen someone should not currently have access, choose the action that matches\nthe situation. A temporary hold, a cancelled invitation and a permanent\noffboarding are different outcomes. Selecting the right one keeps the member\nrecord, future recovery and audit history understandable.\n\n## What you need and what success looks like\n\n| | |\n| --- | --- |\n| **Who performs this task** | An organization owner or administrator responsible for offboarding or temporary access holds |\n| **Where the change applies** | One membership in the selected organization; other organization memberships are separate |\n| **Before you begin** | Determine whether access may return, whether SCIM owns the person, whether credentials also need incident response, and whether another usable owner exists |\n| **Successful result** | A pending invitation is revoked, an active membership is suspended, or the membership is removed—matching the approved lifecycle decision |\n\n## Open the membership you need to change\n\n1. Select the intended organization.\n2. Open **Settings**, then the organization’s **Members** area.\n3. Find the person and confirm their current **Status** and **Roles**.\n4. Choose the lifecycle action that matches the decision below. Do not edit\n roles merely to imitate a suspension or removal.\n\nFor automated offboarding, use the membership lifecycle API operations linked\nfrom this page. Confirm the selected operation supports the member’s current\nstate before sending the request.\n\n> **Choose the lifecycle action, not a cosmetic substitute.** Removing every\n> role is not the same as suspending or removing a membership. Authority is\n> derived from the current active membership on subsequent authenticated\n> requests, so the membership state must express the intended outcome.\n\n~~~mermaid\nflowchart LR\n accTitle: Choose how to end or pause user access\n accDescr: Revoke a pending invitation. For an active membership, suspend access when it will return or remove the membership when it will not.\n start[\"Access must change\"] --> pending{\"Invitation accepted?\"}\n pending -->|\"No\"| revoke[\"Revoke invitation\"]\n pending -->|\"Yes\"| returnLikely{\"Will access return?\"}\n returnLikely -->|\"Yes\"| suspend[\"Suspend membership\"]\n returnLikely -->|\"No\"| remove[\"Remove membership\"]\n suspend --> reactivate[\"Reactivate after the hold clears\"]\n~~~\n\n## Choose the right outcome\n\n| Situation | Use this action | What it means |\n| --- | --- | --- |\n| The person has not accepted the invitation and should not join | Revoke the invitation | Withdraw the pending offer; do not turn it into an active membership |\n| The person should temporarily lose access | Suspend the membership | Keep the membership record while access is on hold; reactivate only when the hold is cleared |\n| The person has left this organization or must permanently lose this organization access | Remove the membership | End this organization relationship and its roles |\n\n{{CONSUMER_FACT:source:consumer-fact:organization-membership-administration#markdown}}\n\n## Protect organization administration first\n\nBefore suspending, removing or reducing the access of an organization owner,\nmake sure another active member can administer the organization. The last\nusable owner cannot be suspended, removed or stripped of the authority that\nkeeps the organization manageable. If the application refuses the action,\ncreate and verify replacement owner coverage before trying again.\n\n## Complete the access decision\n\nBefore applying the change, answer these questions:\n\n- Is the person still expected to return?\n- Is the membership **Invited**, **Active**, **Suspended**, or **Inactive** now?\n- Is another active, usable owner in place when this person carries owner\n authority?\n- Does a directory own this person’s lifecycle?\n- Is there a separate credential or security incident that must be handled too?\n\nFor a suspension, tell the person and the relevant access owner why access is\non hold, then verify the membership state. For removal, confirm that the person\nno longer has the organization membership you intended to remove. Removing the\nmembership also removes the unit assignments that depended on it; it does not\ndelete an organization unit or the person’s memberships in other organizations.\n\nReview the corresponding audit record so the organization can later answer who\nchanged access, for whom, which prior roles and unit assignments were affected,\nand why.\n\nMembership access and credential risk are different concerns. If you suspect a\ncompromised account, follow the organization’s account-security response as\nwell as changing membership access. Do not leave a pending invitation active\nwhile investigating an identity concern.\n\n## Do not compete with SCIM\n\nIf an identity directory owns this person through SCIM, make the lifecycle\nchange in that directory and let the synchronization process apply it. Manual\nexceptions should be deliberate and documented. See [Provision users with\nSCIM](/user-administration/scim-provisioning) for the directory-managed path.\n\n### When should you suspend instead of remove?\n\nSuspend when access is intentionally temporary—for example during a leave,\ninvestigation, or short-term hold—and the same organization relationship is\nexpected to continue. Remove when the relationship has ended and should not be\nreactivated as the same membership.\n\n### Is changing membership enough after a suspected compromise?\n\nNo. Membership state controls organization authority; it does not by itself\ncomplete credential revocation, session response, factor recovery, or incident\ninvestigation. Follow the account-security process as well.\n\n### Why did the application refuse the offboarding action?\n\nIf the person is the last usable owner, the organization would become\nunmanageable. Establish and verify another active owner first. A refusal can\nalso indicate that SCIM owns the lifecycle or that the requested state\ntransition is not valid from the current membership state.";
152
+ readonly sourceRefs: readonly ["saas-technical-doc:engine-content/suspend-or-remove-user"];
153
+ readonly markdown: "# Suspend or remove a user\n\nWhen someone should not currently have access, choose the action that matches\nthe situation. A temporary hold, a cancelled invitation and a permanent\noffboarding are different outcomes. Selecting the right one keeps the member\nrecord, future recovery and audit history understandable.\n\n## What you need and what success looks like\n\n| | |\n| --- | --- |\n| **Who performs this task** | An organization owner or administrator responsible for offboarding or temporary access holds |\n| **Where the change applies** | One membership in the selected organization; other organization memberships are separate |\n| **Before you begin** | Determine whether access may return, whether SCIM owns the person, whether credentials also need incident response, and whether another usable owner exists |\n| **Successful result** | A pending invitation is revoked, an active membership is suspended, or the membership is removed—matching the approved lifecycle decision |\n\n## Open the membership you need to change\n\n1. Select the intended organization.\n2. Open **Settings**, then the organization’s **Members** area.\n3. Find the person and confirm their current **Status** and **Roles**.\n4. Choose the lifecycle action that matches the decision below. Do not edit\n roles merely to imitate a suspension or removal.\n\nFor automated offboarding, use the membership lifecycle API operations linked\nfrom this page. Confirm the selected operation supports the member’s current\nstate before sending the request.\n\n> **Choose the lifecycle action, not a cosmetic substitute.** Removing every\n> role is not the same as suspending or removing a membership. Authority is\n> derived from the current active membership on subsequent authenticated\n> requests, so the membership state must express the intended outcome.\n\n~~~mermaid\nflowchart LR\n accTitle: Choose how to end or pause user access\n accDescr: Revoke a pending invitation. For an active membership, suspend access when it will return or remove the membership when it will not.\n start[\"Access must change\"] --> pending{\"Invitation accepted?\"}\n pending -->|\"No\"| revoke[\"Revoke invitation\"]\n pending -->|\"Yes\"| returnLikely{\"Will access return?\"}\n returnLikely -->|\"Yes\"| suspend[\"Suspend membership\"]\n returnLikely -->|\"No\"| remove[\"Remove membership\"]\n suspend --> reactivate[\"Reactivate after the hold clears\"]\n~~~\n\n## Choose the right outcome\n\n| Situation | Use this action | What it means |\n| --- | --- | --- |\n| The person has not accepted the invitation and should not join | Revoke the invitation | Withdraw the pending offer; do not turn it into an active membership |\n| The person should temporarily lose access | Suspend the membership | Keep the membership record while access is on hold; reactivate only when the hold is cleared |\n| The person has left this organization or must permanently lose this organization access | Remove the membership | End this organization relationship and its roles |\n\nMembership states, the roles available in this application and the last-owner rule are listed once, on [Roles and permissions](/user-administration/roles-and-permissions).\n\n## Protect organization administration first\n\nBefore suspending, removing or reducing the access of an organization owner,\nmake sure another active member can administer the organization. The last\nusable owner cannot be suspended, removed or stripped of the authority that\nkeeps the organization manageable. If the application refuses the action,\ncreate and verify replacement owner coverage before trying again.\n\n## Complete the access decision\n\nBefore applying the change, answer these questions:\n\n- Is the person still expected to return?\n- Is the membership **Invited**, **Active**, **Suspended**, or **Inactive** now?\n- Is another active, usable owner in place when this person carries owner\n authority?\n- Does a directory own this person’s lifecycle?\n- Is there a separate credential or security incident that must be handled too?\n\nFor a suspension, tell the person and the relevant access owner why access is\non hold, then verify the membership state. For removal, confirm that the person\nno longer has the organization membership you intended to remove. Removing the\nmembership also removes the unit assignments that depended on it; it does not\ndelete an organization unit or the person’s memberships in other organizations.\n\nReview the corresponding audit record so the organization can later answer who\nchanged access, for whom, which prior roles and unit assignments were affected,\nand why.\n\nMembership access and credential risk are different concerns. If you suspect a\ncompromised account, follow the organization’s account-security response as\nwell as changing membership access. Do not leave a pending invitation active\nwhile investigating an identity concern.\n\n## Do not compete with SCIM\n\nIf an identity directory owns this person through SCIM, make the lifecycle\nchange in that directory and let the synchronization process apply it. Manual\nexceptions should be deliberate and documented. See [Provision users with\nSCIM](/user-administration/scim-provisioning) for the directory-managed path.\n\n### When should you suspend instead of remove?\n\nSuspend when access is intentionally temporary—for example during a leave,\ninvestigation, or short-term hold—and the same organization relationship is\nexpected to continue. Remove when the relationship has ended and should not be\nreactivated as the same membership.\n\n### Is changing membership enough after a suspected compromise?\n\nNo. Membership state controls organization authority; it does not by itself\ncomplete credential revocation, session response, factor recovery, or incident\ninvestigation. Follow the account-security process as well.\n\n### Why did the application refuse the offboarding action?\n\nIf the person is the last usable owner, the organization would become\nunmanageable. Establish and verify another active owner first. A refusal can\nalso indicate that SCIM owns the lifecycle or that the requested state\ntransition is not valid from the current membership state.";
154
154
  }, {
155
155
  readonly managedPath: "user-administration/review-users-and-access.md";
156
156
  readonly unitRef: "technical-documentation:unit/review-users-and-access";
157
- readonly sourceRefs: readonly ["saas-technical-doc:engine-content/review-users-and-access", "source:consumer-fact:organization-membership-administration"];
158
- readonly markdown: "# Review users and access\n\nReview who can use the organization, why they have that access and whether the\nassignment is still appropriate. Run this review on a regular schedule and\nafter reorganizations, directory changes or security incidents. The outcome is\na reconciled list of memberships, roles and unit assignments with a named owner\nfor every exception.\n\n## What you need and what success looks like\n\n| | |\n| --- | --- |\n| **Who performs this task** | An organization owner, administrator or delegated access reviewer with permission to inspect membership data |\n| **Where the review applies** | One named organization and one defined review date |\n| **Before you begin** | Gather business owners, the directory population when SCIM is used, and the criteria for privileged or exceptional access |\n| **Successful result** | Every membership and unit assignment has a keep, change, suspend or remove decision, with an owner and follow-up date for each exception |\n\n## Open the review population\n\n1. Select the organization being reviewed.\n2. Open **Settings**, then **Members**.\n3. Review the full member directory, not only active people. Include\n **Invited**, **Active**, **Suspended** and **Inactive** memberships.\n4. Use the available status, role and search controls to form review groups,\n but retain one complete population count so filters cannot hide an exception.\n\nFor an automated inventory, use the member-list API operations linked from this\npage and retain the review date and pagination basis with the result.\n\n~~~mermaid\nflowchart LR\n accTitle: Review access from broad membership to narrow assignments\n accDescr: Begin with every organization membership, identify privileged and exceptional access, inspect unit assignments, then reconcile directory-owned records and record decisions.\n members[\"All memberships\"] --> states[\"Membership states\"]\n states --> privileged[\"Owners and privileged roles\"]\n privileged --> units[\"Organization-unit assignments\"]\n units --> ownership[\"Manual or directory ownership\"]\n ownership --> decision[\"Keep, change, suspend or remove\"]\n~~~\n\nStart broad so an invited, suspended or inactive record is not omitted simply\nbecause it cannot currently authorize an operation. Then narrow the review to\nthe access that carries the most business or administrative impact.\n\n{{CONSUMER_FACT:source:consumer-fact:organization-membership-administration#markdown}}\n\n## Prepare the review\n\n- Choose one organization and a clear review date.\n- Name the administrator who will decide on exceptions and the people who own\n each business area.\n- Obtain the current membership list, role assignments and organization-unit\n assignments from the application.\n- Obtain the directory population and status when SCIM owns any members.\n- Define which roles or unit roots count as privileged for this organization.\n\n## Review every membership state\n\n| State | Question to answer | Typical decision |\n| --- | --- | --- |\n| **Invited** | Is the invitation still expected and controlled by the intended email owner? | Keep with an expiry decision or revoke it |\n| **Active** | Does the person still need this organization and these roles? | Keep, reduce, suspend or remove |\n| **Suspended** | Is the temporary hold still justified and is there a named recovery condition? | Reactivate, keep with review date, or remove |\n| **Inactive** | Is the record expected from directory deactivation or another lifecycle decision? | Reconcile with the authoritative owner; do not reactivate casually |\n\n## Examine privileged and narrow access\n\n1. Identify every usable organization owner and confirm that owner continuity\n does not depend on one person.\n2. Review organization administrators and application-defined roles against the\n work they currently perform.\n3. For each person with several roles, verify that every role has a separate\n reason; do not assume the highest visible role makes the others harmless.\n4. Review assignments on root or inheriting units, because one assignment can\n reach a whole descendant branch.\n5. Check a representative unit-aware resource and an unrelated unit with the\n person’s own account when practical.\n\n## Reconcile directory-owned people\n\nCompare the application with the identity directory by stable identity,\nmembership state and expected role. Review blank or unmapped departments and\nmanual unit assignments carefully: a supported authoritative reconciliation\ncan remove a competing manual assignment. Correct directory-owned differences\nat the directory or mapping source, not only in the application.\n\n## Close the review\n\nFor each exception, record the person, organization, present access, decision,\nbusiness owner and next review date. Apply changes through the appropriate\nmanual or SCIM path, preserve owner continuity, and use the audit trail to\nconfirm who performed each material change.";
157
+ readonly sourceRefs: readonly ["saas-technical-doc:engine-content/review-users-and-access"];
158
+ readonly markdown: "# Review users and access\n\nReview who can use the organization, why they have that access and whether the\nassignment is still appropriate. Run this review on a regular schedule and\nafter reorganizations, directory changes or security incidents. The outcome is\na reconciled list of memberships, roles and unit assignments with a named owner\nfor every exception.\n\n## What you need and what success looks like\n\n| | |\n| --- | --- |\n| **Who performs this task** | An organization owner, administrator or delegated access reviewer with permission to inspect membership data |\n| **Where the review applies** | One named organization and one defined review date |\n| **Before you begin** | Gather business owners, the directory population when SCIM is used, and the criteria for privileged or exceptional access |\n| **Successful result** | Every membership and unit assignment has a keep, change, suspend or remove decision, with an owner and follow-up date for each exception |\n\n## Open the review population\n\n1. Select the organization being reviewed.\n2. Open **Settings**, then **Members**.\n3. Review the full member directory, not only active people. Include\n **Invited**, **Active**, **Suspended** and **Inactive** memberships.\n4. Use the available status, role and search controls to form review groups,\n but retain one complete population count so filters cannot hide an exception.\n\nFor an automated inventory, use the member-list API operations linked from this\npage and retain the review date and pagination basis with the result.\n\n~~~mermaid\nflowchart LR\n accTitle: Review access from broad membership to narrow assignments\n accDescr: Begin with every organization membership, identify privileged and exceptional access, inspect unit assignments, then reconcile directory-owned records and record decisions.\n members[\"All memberships\"] --> states[\"Membership states\"]\n states --> privileged[\"Owners and privileged roles\"]\n privileged --> units[\"Organization-unit assignments\"]\n units --> ownership[\"Manual or directory ownership\"]\n ownership --> decision[\"Keep, change, suspend or remove\"]\n~~~\n\nStart broad so an invited, suspended or inactive record is not omitted simply\nbecause it cannot currently authorize an operation. Then narrow the review to\nthe access that carries the most business or administrative impact.\n\nMembership states, the roles available in this application and the last-owner rule are listed once, on [Roles and permissions](/user-administration/roles-and-permissions).\n\n## Prepare the review\n\n- Choose one organization and a clear review date.\n- Name the administrator who will decide on exceptions and the people who own\n each business area.\n- Obtain the current membership list, role assignments and organization-unit\n assignments from the application.\n- Obtain the directory population and status when SCIM owns any members.\n- Define which roles or unit roots count as privileged for this organization.\n\n## Review every membership state\n\n| State | Question to answer | Typical decision |\n| --- | --- | --- |\n| **Invited** | Is the invitation still expected and controlled by the intended email owner? | Keep with an expiry decision or revoke it |\n| **Active** | Does the person still need this organization and these roles? | Keep, reduce, suspend or remove |\n| **Suspended** | Is the temporary hold still justified and is there a named recovery condition? | Reactivate, keep with review date, or remove |\n| **Inactive** | Is the record expected from directory deactivation or another lifecycle decision? | Reconcile with the authoritative owner; do not reactivate casually |\n\n## Examine privileged and narrow access\n\n1. Identify every usable organization owner and confirm that owner continuity\n does not depend on one person.\n2. Review organization administrators and application-defined roles against the\n work they currently perform.\n3. For each person with several roles, verify that every role has a separate\n reason; do not assume the highest visible role makes the others harmless.\n4. Review assignments on root or inheriting units, because one assignment can\n reach a whole descendant branch.\n5. Check a representative unit-aware resource and an unrelated unit with the\n person’s own account when practical.\n\n## Reconcile directory-owned people\n\nCompare the application with the identity directory by stable identity,\nmembership state and expected role. Review blank or unmapped departments and\nmanual unit assignments carefully: a supported authoritative reconciliation\ncan remove a competing manual assignment. Correct directory-owned differences\nat the directory or mapping source, not only in the application.\n\n## Close the review\n\nFor each exception, record the person, organization, present access, decision,\nbusiness owner and next review date. Apply changes through the appropriate\nmanual or SCIM path, preserve owner continuity, and use the audit trail to\nconfirm who performed each material change.";
159
159
  }, {
160
160
  readonly managedPath: "user-administration/troubleshoot-user-access.md";
161
161
  readonly unitRef: "technical-documentation:unit/troubleshoot-user-access";
@@ -170,12 +170,12 @@ export declare const APPLICATION_CONSUMER_DOCUMENTATION_AUTHORED_CONTENT_V1: rea
170
170
  readonly managedPath: "user-administration/scim-protocol-and-payloads.md";
171
171
  readonly unitRef: "technical-documentation:unit/scim-protocol-and-payloads";
172
172
  readonly sourceRefs: readonly ["saas-technical-doc:engine-content/scim-protocol-and-payloads", "source:consumer-fact:organization-scim-provisioning"];
173
- readonly markdown: "# SCIM protocol and payload reference\n\nUse this page to decide whether a directory or provisioning bridge is compatible\nwith this application **before** configuring production users. The application\nimplements a focused SCIM 2.0 User service. It is not a generic LDAP endpoint and\nit does not implement SCIM Groups.\n\n## Supported profile at a glance\n\n| Contract | This application supports | Important boundary |\n| --- | --- | --- |\n| Protocol | SCIM 2.0 over HTTPS with `application/scim+json` | SCIM 1.1 and direct LDAP binds are not accepted |\n| Authentication | A dedicated organization SCIM bearer token | The token selects one organization; it is not a user session or ordinary API key |\n| Resources | `Users` plus SCIM discovery documents | `Groups` is not implemented; group assignment can scope which users the provider sends but must not call `/Groups` |\n| User operations | Create, list, read, full replace, partial update and deactivate; Bulk accepts up to 100 operations | Organization-unit reconciliation differs by operation, as shown below |\n| Filtering | User lookup filters with a published maximum result size of 200 | Test the provider’s exact matching query before broad rollout |\n| Password changes | Not supported | Use the configured human sign-in or SSO journey; do not synchronize directory passwords |\n| Sorting and ETags | Not supported | A provider must not require sorting or conditional ETag writes |\n| Request budget | 300 requests per minute for each SCIM token | A 429 response includes retry information; reduce concurrency rather than rotating addresses |\n\nThe public discovery documents are available beneath the SCIM base URL:\n\n~~~text\nGET /ServiceProviderConfig\nGET /Schemas\nGET /ResourceTypes\n~~~\n\nRead `ServiceProviderConfig` during compatibility testing instead of assuming\nthat every feature mentioned by the SCIM standards is implemented.\n\n## Follow one SCIM request through the application\n\n~~~mermaid\nsequenceDiagram\n accTitle: How the application processes one SCIM User request\n accDescr: The provider sends an authenticated User operation. The SCIM service uses the bearer token to select an organization, validates the operation and profile, matches or creates the identity, maintains the organization membership, performs organization-unit reconciliation only when configured and supported for that operation, and returns a SCIM response.\n participant Provider as Provisioning provider\n participant Endpoint as SCIM endpoint\n participant Scope as Organization boundary\n participant Identity as User and membership\n participant Unit as Organization-unit mapping\n Provider->>Endpoint: User request plus bearer token\n Endpoint->>Scope: Resolve token to one organization\n Scope-->>Endpoint: Authorized organization context\n Endpoint->>Endpoint: Validate operation and SCIM profile\n Endpoint->>Identity: Match, create or update\n opt Mapping enabled and operation supported\n Endpoint->>Unit: Reconcile exact department mapping\n end\n Endpoint-->>Provider: SCIM resource, list or error response\n~~~\n\nThe token establishes the organization boundary **before** the profile is\napplied. The service then validates the request, resolves the person, maintains\nthe organization membership and, for the operations shown below, may reconcile\norganization-unit assignments. The response does not create a browser session\nand does not prove that the person can complete SSO.\n\n### Compatibility questions to answer before configuration\n\n| Provider requirement | Compatible expectation |\n| --- | --- |\n| Discovery | The provider can read `ServiceProviderConfig`, `Schemas` and `ResourceTypes` and respect the advertised feature set |\n| Resource types | User provisioning works without calling `/Groups` |\n| Update behavior | The provider can operate with the documented PUT/PATCH consequences, especially when department controls unit access |\n| Authentication | The provider can send the dedicated bearer token in the HTTPS `Authorization` header |\n| Matching and pagination | Its exact user filter and result-window behavior work within the published limit |\n| Unsupported features | It does not require password synchronization, sorting or conditional ETag writes |\n| Request volume | It respects rate-limit responses and does not depend on Bulk for organization-unit reconciliation |\n\n## Understand the base URL\n\nThe configuration resource supplies the API-relative path\n`/api/v1/scim/v2`. A provider needs the complete public URL:\n\n~~~text\nhttps://api.example.com/api/v1/scim/v2\n~~~\n\nThe organization is not encoded in that URL. The bearer token identifies the\norganization and must therefore be unique to one provider connection and one\nenvironment.\n\n## Example User document\n\nThe following payload shows the fields used by the maintained profile mapping\nand optional organization-unit mapping. Replace every value with a controlled\ntest identity; never copy a real person into documentation or a support ticket.\n\n~~~json\n{\n \"schemas\": [\n \"urn:ietf:params:scim:schemas:core:2.0:User\",\n \"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User\"\n ],\n \"externalId\": \"directory-user-001\",\n \"userName\": \"alex.morgan@example.com\",\n \"active\": true,\n \"name\": {\n \"givenName\": \"Alex\",\n \"familyName\": \"Morgan\"\n },\n \"displayName\": \"Alex Morgan\",\n \"emails\": [{\n \"value\": \"alex.morgan@example.com\",\n \"type\": \"work\",\n \"primary\": true\n }],\n \"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User\": {\n \"department\": \"Engineering\"\n }\n}\n~~~\n\nThe email mapping may use `userName`, the primary email or another configured\nemail path. Department is read from the standard Enterprise User extension; a\ntop-level `department` is accepted as a compatibility fallback. Its value is\nmatched exactly, after trimming, against the organization-unit mapping.\n\n{{CONSUMER_FACT:source:consumer-fact:organization-scim-provisioning#attributeMappingMarkdown}}\n\n## Choose operations with their consequences visible\n\n| Provider operation | User/profile effect | Organization-unit effect |\n| --- | --- | --- |\n| `POST /Users` | Creates or links the person according to the lifecycle configuration | Reconciles an exact mapped department when unit mapping and a default unit role are configured |\n| `PUT /Users/{id}` | Replaces the maintained profile and active state | Performs authoritative unit reconciliation from the full department value |\n| `PATCH /Users/{id}` | Applies supported partial profile or active-state changes | **Does not currently reconcile organization units** |\n| `DELETE /Users/{id}` | Runs the configured deactivation behavior; it does not physically erase the person | Does not perform a department-to-unit reconciliation |\n| `POST /Bulk` | Executes supported user operations individually | **Does not currently reconcile organization units**, including Bulk PUT operations |\n\nThis difference matters with providers that normally send PATCH. Do not enable\nauthoritative department-to-unit mapping merely because user creation worked.\nCapture the operation used for a department move and confirm that the former\nunit assignment is actually removed.\n\n## Recognize a valid list and error response\n\nA successful lookup with no match is a 200 response containing an empty SCIM\nlist—not a 404:\n\n~~~json\n{\n \"schemas\": [\"urn:ietf:params:scim:api:messages:2.0:ListResponse\"],\n \"totalResults\": 0,\n \"startIndex\": 1,\n \"itemsPerPage\": 0,\n \"Resources\": []\n}\n~~~\n\nErrors use the SCIM error media type and may include a `scimType` such as\n`invalidFilter`, `uniqueness`, `invalidSyntax`, `invalidPath` or\n`tooMany`. Preserve the HTTP status, SCIM type, redacted detail, operation,\nprovider job identifier and time. Never preserve the bearer token.\n\n## Standards used by this profile\n\n- [RFC 7643 §4.1](https://www.rfc-editor.org/rfc/rfc7643.html#section-4.1)\n defines the SCIM User resource; [§4.3](https://www.rfc-editor.org/rfc/rfc7643.html#section-4.3)\n defines the Enterprise User extension used for `department`.\n- [RFC 7644 §3.4.2](https://www.rfc-editor.org/rfc/rfc7644.html#section-3.4.2)\n defines filtering; [§3.5.1](https://www.rfc-editor.org/rfc/rfc7644.html#section-3.5.1)\n and [§3.5.2](https://www.rfc-editor.org/rfc/rfc7644.html#section-3.5.2)\n distinguish full replacement from PATCH; [§3.7](https://www.rfc-editor.org/rfc/rfc7644.html#section-3.7)\n defines Bulk; and [§3.12](https://www.rfc-editor.org/rfc/rfc7644.html#section-3.12)\n defines SCIM error responses.\n- [RFC 6750 §2.1](https://www.rfc-editor.org/rfc/rfc6750.html#section-2.1)\n defines bearer-token transport in the `Authorization` header. The\n application’s SCIM token lifecycle and authorization policy remain\n application behavior, not a promise made by that RFC.\n\nUse these standards to understand the wire contract. Use this page and the\napplication’s discovery response to understand the implemented profile.";
173
+ readonly markdown: "# SCIM protocol and payload reference\n\nUse this page to decide whether a directory or provisioning bridge is compatible\nwith this application **before** configuring production users. The application\nimplements a focused SCIM 2.0 User service. It is not a generic LDAP endpoint and\nit does not implement SCIM Groups.\n\n## Supported profile at a glance\n\n| Contract | This application supports | Important boundary |\n| --- | --- | --- |\n| Protocol | SCIM 2.0 over HTTPS with `application/scim+json` | SCIM 1.1 and direct LDAP binds are not accepted |\n| Authentication | A dedicated organization SCIM bearer token | The token selects one organization; it is not a user session or ordinary API key |\n| Resources | `Users` plus SCIM discovery documents | `Groups` is not implemented; group assignment can scope which users the provider sends but must not call `/Groups` |\n| User operations | Create, list, read, full replace, partial update and deactivate; Bulk accepts up to 100 operations | Organization-unit reconciliation differs by operation, as shown below |\n| Filtering | User lookup filters with a published maximum result size of 200 | Test the provider’s exact matching query before broad rollout |\n| Password changes | Not supported | Use the configured human sign-in or SSO journey; do not synchronize directory passwords |\n| Sorting and ETags | Not supported | A provider must not require sorting or conditional ETag writes |\n| Request budget | 300 requests per minute for each SCIM token | A 429 response includes retry information; reduce concurrency rather than rotating addresses |\n\nThe public discovery documents are available beneath the SCIM base URL:\n\n~~~text\nGET /ServiceProviderConfig\nGET /Schemas\nGET /ResourceTypes\n~~~\n\nRead `ServiceProviderConfig` during compatibility testing instead of assuming\nthat every feature mentioned by the SCIM standards is implemented.\n\n## Follow one SCIM request through the application\n\n~~~mermaid\nsequenceDiagram\n accTitle: How the application processes one SCIM User request\n accDescr: The provider sends an authenticated User operation. The SCIM service uses the bearer token to select an organization, validates the operation and profile, matches or creates the identity, maintains the organization membership, performs organization-unit reconciliation only when configured and supported for that operation, and returns a SCIM response.\n participant Provider as Provisioning provider\n participant Endpoint as SCIM endpoint\n participant Scope as Organization boundary\n participant Identity as User and membership\n participant Unit as Organization-unit mapping\n Provider->>Endpoint: User request plus bearer token\n Endpoint->>Scope: Resolve token to one organization\n Scope-->>Endpoint: Authorized organization context\n Endpoint->>Endpoint: Validate operation and SCIM profile\n Endpoint->>Identity: Match, create or update\n opt Mapping enabled and operation supported\n Endpoint->>Unit: Reconcile exact department mapping\n end\n Endpoint-->>Provider: SCIM resource, list or error response\n~~~\n\nThe token establishes the organization boundary **before** the profile is\napplied. The service then validates the request, resolves the person, maintains\nthe organization membership and, for the operations shown below, may reconcile\norganization-unit assignments. The response does not create a browser session\nand does not prove that the person can complete SSO.\n\n### Compatibility questions to answer before configuration\n\n| Provider requirement | Compatible expectation |\n| --- | --- |\n| Discovery | The provider can read `ServiceProviderConfig`, `Schemas` and `ResourceTypes` and respect the advertised feature set |\n| Resource types | User provisioning works without calling `/Groups` |\n| Update behavior | The provider can operate with the documented PUT/PATCH consequences, especially when department controls unit access |\n| Authentication | The provider can send the dedicated bearer token in the HTTPS `Authorization` header |\n| Matching and pagination | Its exact user filter and result-window behavior work within the published limit |\n| Unsupported features | It does not require password synchronization, sorting or conditional ETag writes |\n| Request volume | It respects rate-limit responses and does not depend on Bulk for organization-unit reconciliation |\n\n## Understand the base URL\n\nThe configuration resource supplies the API-relative path\n`/api/v1/scim/v2`. A provider needs the complete public URL:\n\n~~~text\nhttps://api.example.com/api/v1/scim/v2\n~~~\n\nThe organization is not encoded in that URL. The bearer token identifies the\norganization and must therefore be unique to one provider connection and one\nenvironment.\n\n## Example User document\n\nThe following payload shows the fields used by the maintained profile mapping\nand optional organization-unit mapping. Replace every value with a controlled\ntest identity; never copy a real person into documentation or a support ticket.\n\n~~~json\n{\n \"schemas\": [\n \"urn:ietf:params:scim:schemas:core:2.0:User\",\n \"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User\"\n ],\n \"externalId\": \"directory-user-001\",\n \"userName\": \"alex.morgan@example.com\",\n \"active\": true,\n \"name\": {\n \"givenName\": \"Alex\",\n \"familyName\": \"Morgan\"\n },\n \"displayName\": \"Alex Morgan\",\n \"emails\": [{\n \"value\": \"alex.morgan@example.com\",\n \"type\": \"work\",\n \"primary\": true\n }],\n \"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User\": {\n \"department\": \"Engineering\"\n }\n}\n~~~\n\nThe email mapping may use `userName`, the primary email or another configured\nemail path. Department is read from the standard Enterprise User extension; a\ntop-level `department` is accepted as a compatibility fallback. Its value is\nmatched exactly, after trimming, against the organization-unit mapping.\n\n{{CONSUMER_FACT:source:consumer-fact:organization-scim-provisioning#attributeMappingMarkdown}}\n\n## Choose operations with their consequences visible\n\n| Provider operation | User/profile effect | Organization-unit effect |\n| --- | --- | --- |\n| `POST /Users` | Creates or links the person according to the lifecycle configuration | Reconciles an exact mapped department when unit mapping and a default unit role are configured |\n| `PUT /Users/{id}` | Replaces the maintained profile and active state | Performs authoritative unit reconciliation from the full department value |\n| `PATCH /Users/{id}` | Applies supported partial profile or active-state changes | **Does not currently reconcile organization units** |\n| `DELETE /Users/{id}` | Runs the configured deactivation behavior; it does not physically erase the person | Does not perform a department-to-unit reconciliation |\n| `POST /Bulk` | Executes supported user operations individually | **Does not currently reconcile organization units**, including Bulk PUT operations |\n\nThis difference matters with providers that normally send PATCH. Do not enable\nauthoritative department-to-unit mapping merely because user creation worked.\nCapture the operation used for a department move and confirm that the former\nunit assignment is actually removed.\n\n## Recognize a valid list and error response\n\nA successful lookup with no match is a 200 response containing an empty SCIM\nlist—not a 404:\n\n~~~json\n{\n \"schemas\": [\"urn:ietf:params:scim:api:messages:2.0:ListResponse\"],\n \"totalResults\": 0,\n \"startIndex\": 1,\n \"itemsPerPage\": 0,\n \"Resources\": []\n}\n~~~\n\nErrors use the SCIM error media type and may include a `scimType` of\n`invalidSyntax`, `invalidValue`, `uniqueness` or `tooMany`. Preserve the HTTP status, SCIM type, redacted detail, operation,\nprovider job identifier and time. Never preserve the bearer token.\n\n## Standards used by this profile\n\n- [RFC 7643 §4.1](https://www.rfc-editor.org/rfc/rfc7643.html#section-4.1)\n defines the SCIM User resource; [§4.3](https://www.rfc-editor.org/rfc/rfc7643.html#section-4.3)\n defines the Enterprise User extension used for `department`.\n- [RFC 7644 §3.4.2](https://www.rfc-editor.org/rfc/rfc7644.html#section-3.4.2)\n defines filtering; [§3.5.1](https://www.rfc-editor.org/rfc/rfc7644.html#section-3.5.1)\n and [§3.5.2](https://www.rfc-editor.org/rfc/rfc7644.html#section-3.5.2)\n distinguish full replacement from PATCH; [§3.7](https://www.rfc-editor.org/rfc/rfc7644.html#section-3.7)\n defines Bulk; and [§3.12](https://www.rfc-editor.org/rfc/rfc7644.html#section-3.12)\n defines SCIM error responses.\n- [RFC 6750 §2.1](https://www.rfc-editor.org/rfc/rfc6750.html#section-2.1)\n defines bearer-token transport in the `Authorization` header. The\n application’s SCIM token lifecycle and authorization policy remain\n application behavior, not a promise made by that RFC.\n\nUse these standards to understand the wire contract. Use this page and the\napplication’s discovery response to understand the implemented profile.";
174
174
  }, {
175
175
  readonly managedPath: "user-administration/scim-configure.md";
176
176
  readonly unitRef: "technical-documentation:unit/scim-configure";
177
177
  readonly sourceRefs: readonly ["saas-technical-doc:engine-content/scim-configure", "source:consumer-fact:organization-scim-provisioning"];
178
- readonly markdown: "# Configure SCIM provisioning\n\nConfigure the lifecycle rules and a dedicated credential before you send any\nproduction user. This page is for an organization administrator working with\nthe identity team that owns the directory connection.\n\n## What you need and what success looks like\n\n| | |\n| --- | --- |\n| **Who performs this task** | An organization owner or administrator together with the identity-directory owner |\n| **Where the configuration applies** | One selected organization and one directory environment |\n| **Before you begin** | Prove enterprise sign-in, choose lifecycle defaults, create any mapped units and prepare a protected secret store |\n| **Successful result** | The provisioning configuration and a dedicated active token exist, and a controlled SCIM user operation produces the expected application state |\n\n## Open SCIM administration\n\n1. Select the organization the directory will manage.\n2. Open **Settings**, then the organization’s **User provisioning** area.\n3. Use **Provisioning** for lifecycle defaults, attribute mappings and unit\n mappings.\n4. Use **Tokens** to create and manage the directory credential.\n\nIf **User provisioning** is absent, do not infer that SCIM is enabled. Confirm\nthe organization entitlement and application capability with the application\nowner. For automation, use the SCIM configuration and token API references\nlinked from this section.\n\n## Confirm the prerequisites\n\n- The organization type allows SCIM. The provisioning record has no separate\n `scimEnabled` switch.\n- Enterprise sign-in works for a representative directory-managed person.\n- You have selected a least-privileged default organization role.\n- Any organization units referenced by the directory already exist.\n- You know whether trusted directory assertions verify email and whether\n directory deactivation should change application access.\n\n## Configure the lifecycle decisions\n\nThe configuration below is projected from the maintained SCIM resource\nspecification and schema. The API reference remains authoritative for its exact\nrequest shape; this table explains what each value changes operationally.\n\n{{CONSUMER_FACT:source:consumer-fact:organization-scim-provisioning#configurationMarkdown}}\n\nThe standard **Organization owner** and **Organization administrator** roles\ncannot be SCIM defaults. Review every custom role’s effective inheritance before\nusing it for automatic provisioning.\n\n### Example: cautious first configuration\n\n~~~json\n{\n \"autoCreateUsers\": true,\n \"autoVerifyEmail\": true,\n \"autoDeactivateUsers\": false,\n \"defaultRole\": \"organization-member\",\n \"attributeMapping\": {\n \"email\": \"emails[primary eq true].value\",\n \"firstName\": \"name.givenName\",\n \"lastName\": \"name.familyName\",\n \"displayName\": \"displayName\"\n }\n}\n~~~\n\nThis example deliberately leaves automatic deactivation off for the first\ncontrolled tests. It is not a recommended permanent policy: before production,\ndecide who owns leaver access and prove the multi-organization consequence\ndescribed below. Replace the example role with one from this application’s\n[Roles and permissions](/user-administration/roles-and-permissions) page.\n\n## Create the directory credential\n\nUse the application’s public API origin with the SCIM base path:\n\n~~~text\n/api/v1/scim/v2\n~~~\n\nSend a dedicated bearer token:\n\n~~~http\nAuthorization: Bearer SCIM_TOKEN\n~~~\n\nCreate a separate token for each directory connection and environment. The\nplaintext secret is returned once; store it immediately in the identity\nprovider’s secret store. Keep it out of source control, screenshots, logs,\ntickets and reusable examples.\n\nThe current request budget is **300 requests per minute per token**. When the\nservice returns a rate limit, follow its retry information and reduce\nconcurrency instead of starting parallel retries.\n\n## Treat deactivation as a high-impact choice\n\nThe current deactivation path marks both the global user and the addressed\norganization membership inactive. For a person who belongs to several\norganizations, this can affect more than the directory-owned membership. Test\nthat case before production rollout. A later `active:true` does not prove that\nthe organization membership was restored; verify both layers before announcing\nrecovery.";
178
+ readonly markdown: "# Configure SCIM provisioning\n\nConfigure the lifecycle rules and a dedicated credential before you send any\nproduction user. This page is for an organization administrator working with\nthe identity team that owns the directory connection.\n\n## What you need and what success looks like\n\n| | |\n| --- | --- |\n| **Who performs this task** | An organization owner or administrator together with the identity-directory owner |\n| **Where the configuration applies** | One selected organization and one directory environment |\n| **Before you begin** | Prove enterprise sign-in, choose lifecycle defaults, create any mapped units and prepare a protected secret store |\n| **Successful result** | The provisioning configuration and a dedicated active token exist, and a controlled SCIM user operation produces the expected application state |\n\n## Open SCIM administration\n\n1. Select the organization the directory will manage.\n2. Open **Settings**, then the organization’s **User provisioning** area.\n3. Use **Provisioning** for lifecycle defaults, attribute mappings and unit\n mappings.\n4. Use **Tokens** to create and manage the directory credential.\n\nIf **User provisioning** is absent, do not infer that SCIM is enabled. Confirm\nthe organization entitlement and application capability with the application\nowner. For automation, use the SCIM configuration and token API references\nlinked from this section.\n\n## Confirm the prerequisites\n\n- The organization type allows SCIM. The provisioning record has no separate\n `scimEnabled` switch.\n- Enterprise sign-in works for a representative directory-managed person.\n- You have selected a least-privileged default organization role.\n- Any organization units referenced by the directory already exist.\n- You know whether trusted directory assertions verify email and whether\n directory deactivation should change application access.\n\n## Configure the lifecycle decisions\n\nThe configuration below is projected from the maintained SCIM resource\nspecification and schema. The API reference remains authoritative for its exact\nrequest shape; this table explains what each value changes operationally.\n\n{{CONSUMER_FACT:source:consumer-fact:organization-scim-provisioning#configurationMarkdown}}\n\nThe standard **Organization owner** and **Organization administrator** roles\ncannot be SCIM defaults. Review every custom role’s effective inheritance before\nusing it for automatic provisioning.\n\n### Example: cautious first configuration\n\n~~~json\n{\n \"autoCreateUsers\": true,\n \"autoVerifyEmail\": true,\n \"autoDeactivateUsers\": false,\n \"defaultRole\": \"ORG_MEMBER\",\n \"attributeMapping\": {\n \"email\": \"emails[primary eq true].value\",\n \"firstName\": \"name.givenName\",\n \"lastName\": \"name.familyName\",\n \"displayName\": \"displayName\"\n }\n}\n~~~\n\nThis example deliberately leaves automatic deactivation off for the first\ncontrolled tests. It is not a recommended permanent policy: before production,\ndecide who owns leaver access and prove the multi-organization consequence\ndescribed below. Replace the example role with one from this application’s\n[Roles and permissions](/user-administration/roles-and-permissions) page.\n\n## Create the directory credential\n\nUse the application’s public API origin with the SCIM base path:\n\n~~~text\n/api/v1/scim/v2\n~~~\n\nSend a dedicated bearer token:\n\n~~~http\nAuthorization: Bearer SCIM_TOKEN\n~~~\n\nCreate a separate token for each directory connection and environment. The\nplaintext secret is returned once; store it immediately in the identity\nprovider’s secret store. Keep it out of source control, screenshots, logs,\ntickets and reusable examples.\n\nThe current request budget is **300 requests per minute per token**. When the\nservice returns a rate limit, follow its retry information and reduce\nconcurrency instead of starting parallel retries.\n\n## Treat deactivation as a high-impact choice\n\nThe current deactivation path marks both the global user and the addressed\norganization membership inactive. For a person who belongs to several\norganizations, this can affect more than the directory-owned membership. Test\nthat case before production rollout. A later `active:true` does not prove that\nthe organization membership was restored; verify both layers before announcing\nrecovery.";
179
179
  }, {
180
180
  readonly managedPath: "user-administration/scim-microsoft-entra.md";
181
181
  readonly unitRef: "technical-documentation:unit/scim-microsoft-entra";
@@ -214,8 +214,8 @@ export declare const APPLICATION_CONSUMER_DOCUMENTATION_AUTHORED_CONTENT_V1: rea
214
214
  }, {
215
215
  readonly managedPath: "security-and-audit/investigate-event.md";
216
216
  readonly unitRef: "technical-documentation:unit/investigate-audit-event";
217
- readonly sourceRefs: readonly ["saas-technical-doc:engine-content/investigate-audit-event"];
218
- readonly markdown: "# Investigate an audit event\n\nBegin with a question, not with the entire event stream: “Why was this request\nrefused?”, “Who changed this person's role?” or “What happened after this\ncredential was used?” Choose the smallest time range and organization that can\nanswer it.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Have one reviewable question, the intended organization/environment, an approximate time and any event, correlation, resource or actor identifier already known | The relevant event chain and actor/outcome are explained, current resource state is reconciled, and any anomaly has an owner without changing the evidence |\n\n~~~mermaid\nflowchart TD\n accTitle: Investigate one audit question from symptom to current state\n accDescr: The investigator defines one bounded question, confirms organization and time, finds a starting event, verifies actor and outcome, follows the correlation, compares event data with current application state, and records either a conclusion or an owned gap.\n question[\"State one question and expected evidence\"] --> scope[\"Confirm environment, organization and time\"]\n scope --> event[\"Find a starting event or bounded absence\"]\n event --> actor[\"Verify actor, subject, source and outcome\"]\n actor --> correlation[\"Follow correlation and related identifiers\"]\n correlation --> current[\"Compare with current authoritative state\"]\n current --> conclusion{\"Question answered?\"}\n conclusion -->|\"Yes\"| close[\"Record conclusion and evidence boundaries\"]\n conclusion -->|\"No\"| gap[\"Assign a producer, scope or delivery follow-up\"]\n~~~\n\nWrite down what you expected to find before opening the stream. This prevents a\nlarge number of unrelated events from changing the original question.\n\n## Read the event in layers\n\n| Evidence | Question it answers |\n| --- | --- |\n| **Event ID** | Which single event is this across audit stores and exported copies? |\n| **Correlation ID** | Which request, job or scheduled action produced this and related events? |\n| **Event type, category and severity** | What kind of activity is this and how should review be prioritized? |\n| **Actor and source** | Which person, machine or system initiated the action, and from which surface? |\n| **Organization and application** | Which scope is the event about? |\n| **Outcome and reason** | Did the action succeed or fail, and why? |\n| **Event data** | Which event-specific identifiers and before/after facts were recorded? |\n\nAn actor and a subject are not always the same person. A machine or system may\nalso be the honest actor. **Unattributed** means a principal was expected but\ncould not be resolved; treat that as an investigation signal rather than\nsilently relabelling it as “system.”\n\nSeverity helps prioritize review; it is not a verdict that an action was\nmalicious. A successful role grant can remain important because of the authority\nit creates. Conversely, repeated refusals can be more significant as a pattern\nthan any single event.\n\n## Follow one correlation\n\n1. Verify the organization and environment.\n2. Read the event outcome before inferring that a change took effect.\n3. Filter by correlation ID to find events from the same request.\n4. Compare event-specific before/after evidence with the current authoritative\n resource state.\n5. Pivot to application logs or errors using the same correlation ID when\n operational detail is needed.\n\nWhen the event concerns access, also identify the credential or membership that\ncarried authority. For a machine actor, compare the API key or OAuth client\nprefix, scope and roles. For a person, compare the organization membership and\nrole. For a system actor, identify the scheduled or lifecycle process rather\nthan inventing a human owner.\n\n## Interpret outcome and time carefully\n\n- **Success** means the recorded action completed at that point; compare current\n state for later changes.\n- **Failure** means the action was refused or failed; it does not prove that no\n earlier or later attempt succeeded.\n- A before/after value explains that recorded transition, not every change to\n the resource.\n- Similar timestamps do not make two events the same action; use correlation,\n event identifiers and affected-resource identifiers.\n- A missing event after filtering can mean wrong organization, time zone,\n category/type, actor or producer expectation. Widen one boundary at a time.\n\nDo not assume an enum member proves that an event is emitted. Some declared\nevent names are deliberately superseded by richer generic operation events. The\nstored row is the evidence that an action actually left a trail.\n\n## Close or escalate the investigation\n\nRecord the original question, filters and time zone, event/correlation/resource\nidentifiers, actor interpretation, recorded outcome, current-state comparison\nand conclusion. If the expected evidence is absent, state exactly which\noperation and producer path should have emitted it and preserve a reproducible\ncontrolled scenario. Do not edit an audit row or create a replacement row by\nhand.\n\nShare only the smallest necessary excerpt. Remove credentials, complete tokens\nand unrelated personal data while keeping identifiers needed for another\nauthorized reviewer to reproduce the search.";
217
+ readonly sourceRefs: readonly ["saas-technical-doc:engine-content/investigate-audit-event", "source:consumer-fact:organization-audit-trail"];
218
+ readonly markdown: "# Investigate an audit event\n\nBegin with a question, not with the entire event stream: “Why was this request\nrefused?”, “Who changed this person's role?” or “What happened after this\ncredential was used?” Choose the smallest time range and organization that can\nanswer it.\n\n## What you can narrow the trail by\n\n{{CONSUMER_FACT:source:consumer-fact:organization-audit-trail#queryMarkdown}}\n\nEvery event carries a category and a severity. Both are closed lists, so they are\nthe two filters that reliably cut a broad question down:\n\n{{CONSUMER_FACT:source:consumer-fact:organization-audit-trail#categoriesMarkdown}}\n\n{{CONSUMER_FACT:source:consumer-fact:organization-audit-trail#severitiesMarkdown}}\n\n| Before you begin | Successful result |\n| --- | --- |\n| Have one reviewable question, the intended organization/environment, an approximate time and any event, correlation, resource or actor identifier already known | The relevant event chain and actor/outcome are explained, current resource state is reconciled, and any anomaly has an owner without changing the evidence |\n\n~~~mermaid\nflowchart TD\n accTitle: Investigate one audit question from symptom to current state\n accDescr: The investigator defines one bounded question, confirms organization and time, finds a starting event, verifies actor and outcome, follows the correlation, compares event data with current application state, and records either a conclusion or an owned gap.\n question[\"State one question and expected evidence\"] --> scope[\"Confirm environment, organization and time\"]\n scope --> event[\"Find a starting event or bounded absence\"]\n event --> actor[\"Verify actor, subject, source and outcome\"]\n actor --> correlation[\"Follow correlation and related identifiers\"]\n correlation --> current[\"Compare with current authoritative state\"]\n current --> conclusion{\"Question answered?\"}\n conclusion -->|\"Yes\"| close[\"Record conclusion and evidence boundaries\"]\n conclusion -->|\"No\"| gap[\"Assign a producer, scope or delivery follow-up\"]\n~~~\n\nWrite down what you expected to find before opening the stream. This prevents a\nlarge number of unrelated events from changing the original question.\n\n## Read the event in layers\n\n| Evidence | Question it answers |\n| --- | --- |\n| **Event ID** | Which single event is this across audit stores and exported copies? |\n| **Correlation ID** | Which request, job or scheduled action produced this and related events? |\n| **Event type, category and severity** | What kind of activity is this and how should review be prioritized? |\n| **Actor and source** | Which person, machine or system initiated the action, and from which surface? |\n| **Organization and application** | Which scope is the event about? |\n| **Outcome and reason** | Did the action succeed or fail, and why? |\n| **Event data** | Which event-specific identifiers and before/after facts were recorded? |\n\nAn actor and a subject are not always the same person. A machine or system may\nalso be the honest actor. **Unattributed** means a principal was expected but\ncould not be resolved; treat that as an investigation signal rather than\nsilently relabelling it as “system.”\n\nSeverity helps prioritize review; it is not a verdict that an action was\nmalicious. A successful role grant can remain important because of the authority\nit creates. Conversely, repeated refusals can be more significant as a pattern\nthan any single event.\n\n## Follow one correlation\n\n1. Verify the organization and environment.\n2. Read the event outcome before inferring that a change took effect.\n3. Filter by correlation ID to find events from the same request.\n4. Compare event-specific before/after evidence with the current authoritative\n resource state.\n5. Pivot to application logs or errors using the same correlation ID when\n operational detail is needed.\n\nWhen the event concerns access, also identify the credential or membership that\ncarried authority. For a machine actor, compare the API key or OAuth client\nprefix, scope and roles. For a person, compare the organization membership and\nrole. For a system actor, identify the scheduled or lifecycle process rather\nthan inventing a human owner.\n\n## Interpret outcome and time carefully\n\n- **Success** means the recorded action completed at that point; compare current\n state for later changes.\n- **Failure** means the action was refused or failed; it does not prove that no\n earlier or later attempt succeeded.\n- A before/after value explains that recorded transition, not every change to\n the resource.\n- Similar timestamps do not make two events the same action; use correlation,\n event identifiers and affected-resource identifiers.\n- A missing event after filtering can mean wrong organization, time zone,\n category/type, actor or producer expectation. Widen one boundary at a time.\n\nDo not assume an enum member proves that an event is emitted. Some declared\nevent names are deliberately superseded by richer generic operation events. The\nstored row is the evidence that an action actually left a trail.\n\n## Close or escalate the investigation\n\nRecord the original question, filters and time zone, event/correlation/resource\nidentifiers, actor interpretation, recorded outcome, current-state comparison\nand conclusion. If the expected evidence is absent, state exactly which\noperation and producer path should have emitted it and preserve a reproducible\ncontrolled scenario. Do not edit an audit row or create a replacement row by\nhand.\n\nShare only the smallest necessary excerpt. Remove credentials, complete tokens\nand unrelated personal data while keeping identifiers needed for another\nauthorized reviewer to reproduce the search.";
219
219
  }, {
220
220
  readonly managedPath: "security-and-audit/review-access-changes.md";
221
221
  readonly unitRef: "technical-documentation:unit/review-privileged-and-access-changes";
@@ -249,8 +249,8 @@ export declare const APPLICATION_CONSUMER_DOCUMENTATION_AUTHORED_CONTENT_V1: rea
249
249
  }, {
250
250
  readonly managedPath: "security-and-audit/operate-siem.md";
251
251
  readonly unitRef: "technical-documentation:unit/operate-and-troubleshoot-siem-delivery";
252
- readonly sourceRefs: readonly ["saas-technical-doc:engine-content/operate-and-troubleshoot-siem-delivery"];
253
- readonly markdown: "# Operate and troubleshoot SIEM delivery\n\nThe organization audit record and the SIEM copy have different health signals.\nWhen delivery fails, investigate the delivery queue without treating the source\nevent as missing.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Have the organization/environment, source event ID, destination identity, approximate failure time, current configuration owner and permission to inspect recovery rows | The source event is confirmed, the receiver/configuration fault is corrected, eligible events are re-enqueued or intentionally purged with approval, and delivery is verified without exposing credentials |\n\n~~~mermaid\nflowchart TD\n accTitle: Recover a failed SIEM delivery\n accDescr: A selected audit event is delivered to the configured receiver. Normal retries happen before a failure capture is stored in the dead-letter queue. An authorized retry re-enqueues the stored envelope and removes that recovery row; a later failure creates a new row. Purge removes only recovery rows.\n selected[\"Selected audit event\"] --> attempt[\"Delivery attempt\"]\n attempt -->|Receiver accepts| delivered[\"SIEM copy delivered\"]\n attempt -->|Retry budget remains| attempt\n attempt -->|Delivery cannot continue| captured[\"Failure captured in dead-letter queue\"]\n captured --> inspect[\"Correct receiver, credentials, format or filtering\"]\n inspect -->|Authorized retry| requeue[\"Re-enqueue stored event\"]\n requeue -->|Queue accepts event| remove[\"Remove this recovery row\"]\n remove --> attempt\n captured -->|Authorized purge| purge[\"Remove recovery row without retry\"]\n~~~\n\n## Start from the failure boundary\n\n| Symptom | First checks |\n| --- | --- |\n| No events after enabling | Five-minute configuration cache, organization routing and event filter |\n| Receiver rejects every request | URL, selected format, content type and configured authentication |\n| HMAC verification fails | Exact received bytes and current shared secret; never parse and reserialize first |\n| Repeated timeouts | Receiver availability and configured timeout; reduce work before acknowledgement |\n| Events enter the dead-letter queue | Failure reason, failure count, last attempt and next retry time |\n| Only some event types arrive | Category, minimum severity and specific-event allowlist |\n\nThe delivery service retries with exponential backoff according to the configured\nbudget. Repeated failures can open a scope-specific circuit breaker; affected\nevents go to the dead-letter queue instead of being silently discarded.\n\n## Diagnose in source-to-receiver order\n\n1. Find the authoritative audit row by event ID or the narrowest available\n organization/time filter. If no source row exists, this is not yet a SIEM\n delivery problem.\n2. Confirm that the organization route and current category, severity and event-\n type filters select the event.\n3. Account for the configuration cache after enabling, changing or moving the\n destination.\n4. Inspect the delivery/recovery row for attempt count, last failure and next\n retry state.\n5. Check DNS/TLS reachability, timeout and receiver acknowledgement before\n changing credentials or format.\n6. Verify authentication at the receiver without logging the bearer/API-key/HMAC\n secret. For HMAC, verify the exact received bytes before parsing.\n7. Confirm the receiver parses the selected format into the intended event ID,\n actor, organization, outcome and severity.\n\nChange one boundary at a time and send a new controlled event. Replaying many\nrows before the receiver is corrected creates noise and can reopen the circuit.\n\nRetry a single row or all eligible rows only after correcting the receiver. A\nsuccessful retry action means **the event was accepted back onto the delivery\nqueue**, not that the SIEM has already accepted it. The recovery row is removed\nafter re-enqueue; if delivery fails again, a new dead-letter row records that\nlater failure.\n\n| Recovery action | What it proves | What it does not prove |\n| --- | --- | --- |\n| Retry one/all eligible rows | The stored envelope was accepted back onto the delivery queue | The receiver accepted or indexed it |\n| Receiver acknowledgement | The destination accepted the HTTP delivery | The event was parsed into the intended fields or detection rule |\n| Purge recovery row | The failed-delivery work item was intentionally removed | The source audit event was deleted |\n\nAfter re-enqueue, follow the new delivery outcome and find the event in the SIEM\nby its event ID. Compare critical fields with the source row; do not close on an\nHTTP success alone.\n\nPurging removes delivery-recovery rows, not the authoritative audit events.\nPreserve event ID and failure evidence long enough to prove the recovery result.\nUse purge only when retry is no longer appropriate—for example the receiver or\nevent route was intentionally retired—and retain who approved that loss of the\ndelivery copy.\n\nClose the incident with source event ID, organization/environment, destination,\nfilter decision, failure class, attempts, configuration correction, retry/purge\ndecision, receiver lookup and correlation evidence. Exclude authentication\nsecrets, raw Authorization headers and unnecessary event personal data.";
252
+ readonly sourceRefs: readonly ["saas-technical-doc:engine-content/operate-and-troubleshoot-siem-delivery", "source:consumer-fact:organization-siem-export"];
253
+ readonly markdown: "# Operate and troubleshoot SIEM delivery\n\nThe organization audit record and the SIEM copy have different health signals.\nWhen delivery fails, investigate the delivery queue without treating the source\nevent as missing.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Have the organization/environment, source event ID, destination identity, approximate failure time, current configuration owner and permission to inspect recovery rows | The source event is confirmed, the receiver/configuration fault is corrected, eligible events are re-enqueued or intentionally purged with approval, and delivery is verified without exposing credentials |\n\n~~~mermaid\nflowchart TD\n accTitle: Recover a failed SIEM delivery\n accDescr: A selected audit event is delivered to the configured receiver. Normal retries happen before a failure capture is stored in the dead-letter queue. An authorized retry re-enqueues the stored envelope and removes that recovery row; a later failure creates a new row. Purge removes only recovery rows.\n selected[\"Selected audit event\"] --> attempt[\"Delivery attempt\"]\n attempt -->|Receiver accepts| delivered[\"SIEM copy delivered\"]\n attempt -->|Retry budget remains| attempt\n attempt -->|Delivery cannot continue| captured[\"Failure captured in dead-letter queue\"]\n captured --> inspect[\"Correct receiver, credentials, format or filtering\"]\n inspect -->|Authorized retry| requeue[\"Re-enqueue stored event\"]\n requeue -->|Queue accepts event| remove[\"Remove this recovery row\"]\n remove --> attempt\n captured -->|Authorized purge| purge[\"Remove recovery row without retry\"]\n~~~\n\n## When a destination keeps failing\n\n{{CONSUMER_FACT:source:consumer-fact:organization-siem-export#deliveryReliabilityMarkdown}}\n\n## Start from the failure boundary\n\n| Symptom | First checks |\n| --- | --- |\n| No events after enabling | Five-minute configuration cache, organization routing and event filter |\n| Receiver rejects every request | URL, selected format, content type and configured authentication |\n| HMAC verification fails | Exact received bytes and current shared secret; never parse and reserialize first |\n| Repeated timeouts | Receiver availability and configured timeout; reduce work before acknowledgement |\n| Events enter the dead-letter queue | Failure reason, failure count, last attempt and next retry time |\n| Only some event types arrive | Category, minimum severity and specific-event allowlist |\n\nThe delivery service retries with exponential backoff according to the configured\nbudget. Repeated failures can open a scope-specific circuit breaker; affected\nevents go to the dead-letter queue instead of being silently discarded.\n\n## Diagnose in source-to-receiver order\n\n1. Find the authoritative audit row by event ID or the narrowest available\n organization/time filter. If no source row exists, this is not yet a SIEM\n delivery problem.\n2. Confirm that the organization route and current category, severity and event-\n type filters select the event.\n3. Account for the configuration cache after enabling, changing or moving the\n destination.\n4. Inspect the delivery/recovery row for attempt count, last failure and next\n retry state.\n5. Check DNS/TLS reachability, timeout and receiver acknowledgement before\n changing credentials or format.\n6. Verify authentication at the receiver without logging the bearer/API-key/HMAC\n secret. For HMAC, verify the exact received bytes before parsing.\n7. Confirm the receiver parses the selected format into the intended event ID,\n actor, organization, outcome and severity.\n\nChange one boundary at a time and send a new controlled event. Replaying many\nrows before the receiver is corrected creates noise and can reopen the circuit.\n\nRetry a single row or all eligible rows only after correcting the receiver. A\nsuccessful retry action means **the event was accepted back onto the delivery\nqueue**, not that the SIEM has already accepted it. The recovery row is removed\nafter re-enqueue; if delivery fails again, a new dead-letter row records that\nlater failure.\n\n| Recovery action | What it proves | What it does not prove |\n| --- | --- | --- |\n| Retry one/all eligible rows | The stored envelope was accepted back onto the delivery queue | The receiver accepted or indexed it |\n| Receiver acknowledgement | The destination accepted the HTTP delivery | The event was parsed into the intended fields or detection rule |\n| Purge recovery row | The failed-delivery work item was intentionally removed | The source audit event was deleted |\n\nAfter re-enqueue, follow the new delivery outcome and find the event in the SIEM\nby its event ID. Compare critical fields with the source row; do not close on an\nHTTP success alone.\n\nPurging removes delivery-recovery rows, not the authoritative audit events.\nPreserve event ID and failure evidence long enough to prove the recovery result.\nUse purge only when retry is no longer appropriate—for example the receiver or\nevent route was intentionally retired—and retain who approved that loss of the\ndelivery copy.\n\nClose the incident with source event ID, organization/environment, destination,\nfilter decision, failure class, attempts, configuration correction, retry/purge\ndecision, receiver lookup and correlation evidence. Exclude authentication\nsecrets, raw Authorization headers and unnecessary event personal data.";
254
254
  }, {
255
255
  readonly managedPath: "security-and-audit/protect-evidence.md";
256
256
  readonly unitRef: "technical-documentation:unit/protect-and-retain-audit-evidence";
@@ -269,13 +269,13 @@ export declare const APPLICATION_CONSUMER_DOCUMENTATION_AUTHORED_CONTENT_V1: rea
269
269
  }, {
270
270
  readonly managedPath: "billing-and-subscriptions/start-subscription.md";
271
271
  readonly unitRef: "technical-documentation:unit/start-billing-subscription";
272
- readonly sourceRefs: readonly ["saas-technical-doc:engine-content/start-billing-subscription", "source:consumer-fact:billing-lifecycle"];
273
- readonly markdown: "# Start a subscription\n\nStart a subscription only when you can approve billing for the selected scope.\nFor organization billing, organization owners and administrators are the\nstandard authorized roles. Confirm your application exposes Billing and the\nintended product before beginning.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Have the approved organization, current product and price, expected access, spending approval, protected payment owner and a way to reconcile an unclear result | One checkout creates the intended subscription, the application records its current state and the expected feature or limit works in the billed scope |\n\n> **One checkout attempt can complete even when the browser never returns.**\n> Keep its identifiers and reconcile the application state before opening a\n> replacement checkout.\n\n## Before checkout\n\n1. Select the intended organization before opening Billing. Do not rely on the\n organization that happened to be active in a previous browser session.\n2. Confirm the product, price, currency, interval, quantity, tax display, trial\n terms and expected access against the approval.\n3. Check whether the displayed promotion applies to this exact product and\n price. Visibility of a promotion does not guarantee that every item accepts it.\n4. Record the approver, expected effective date and application action that will\n prove the resulting access.\n5. Continue once to the hosted checkout presented by the application.\n\nPayment details, billing address and tax identifiers belong on that hosted\nbilling surface. Do not send them through application support, an API metadata\nfield or a screenshot.\n\nWhen you enter a promotion code, stop if checkout refuses it. Do not compensate\nby changing quantity, selecting another organization or asking support to copy\nthe discount manually. Recheck the product, validity period, redemption limit\nand discount currency against the approved offer.\n\n~~~mermaid\nsequenceDiagram\n accTitle: Start and verify a subscription\n accDescr: The administrator opens checkout from the application, completes provider-hosted payment, returns to the application, then verifies the application subscription and resulting access instead of trusting the redirect alone.\n participant A as Administrator\n participant App as Application\n participant B as Hosted billing\n A->>App: Select product and price for the intended scope\n App-->>A: Open authorized checkout\n A->>B: Confirm payment and billing details\n B-->>A: Return to application\n App->>App: Verify billing result and update subscription\n A->>App: Read subscription state and expected access\n~~~\n\nThe browser return is only navigation. The application updates its billing\nrecords from the verified provider result, then recomputes access. Closing the\nbrowser, losing the redirect or receiving a timeout does not establish whether\nthe provider completed the checkout.\n\nIf the hosted screen identifies itself as Stripe, see Stripe's maintained\n[subscription Checkout journey](https://docs.stripe.com/billing/subscriptions/build-subscriptions)\nfor the provider-side steps. That reference explains the hosted screen; the\napplication subscription and resulting access remain the completion evidence.\n\n## Confirm success\n\nDo not use the success URL as the success criterion. In the application, verify:\n\n- a subscription exists for the intended billing account;\n- its product, price and period are correct;\n- its state is **Active** or **Trialing**;\n- the expected feature or limit is available in the intended organization;\n- any first invoice has the expected total and state.\n\nUse the maintained subscription meanings when reading the result:\n\n{{CONSUMER_FACT:source:consumer-fact:billing-lifecycle#subscriptionStatusesMarkdown}}\n\nIf the state remains incomplete, past due, unpaid or absent, do not create a\nsecond checkout immediately. Use the troubleshooting and reconciliation pages\nto determine whether the first attempt is still being processed.\n\n### Example: the browser closes after payment\n\nSuppose an administrator approves the Business plan, completes the hosted\npayment, and the browser closes before returning. Reopen Billing in the same\norganization and read the current subscription. If the approved plan is Active\nand the expected limit works, record that result and close the task. If the\nsubscription is absent or Incomplete, preserve the first checkout identifier and\nreconcile it; **do not start another purchase merely to obtain a success page**.\n\n## Verify access, not only billing\n\nRepeat the application action identified before checkout. Confirm it in the\nsame organization and with an ordinary intended user—not only with the billing\nadministrator. Also verify one limit or unavailable action that should remain\nunchanged, so the proof does not hide an unexpectedly broad grant.\n\n## Retain safe completion evidence\n\nKeep the organization, product/price identity, checkout or subscription\nidentifier, visible status, period dates, first-invoice summary, approver,\ncorrelation data and access-verification result. Do not retain card details,\npayment-method data, complete invoice documents, provider secrets or the full\ncheckout URL.";
272
+ readonly sourceRefs: readonly ["saas-technical-doc:engine-content/start-billing-subscription"];
273
+ readonly markdown: "# Start a subscription\n\nStart a subscription only when you can approve billing for the selected scope.\nFor organization billing, organization owners and administrators are the\nstandard authorized roles. Confirm your application exposes Billing and the\nintended product before beginning.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Have the approved organization, current product and price, expected access, spending approval, protected payment owner and a way to reconcile an unclear result | One checkout creates the intended subscription, the application records its current state and the expected feature or limit works in the billed scope |\n\n> **One checkout attempt can complete even when the browser never returns.**\n> Keep its identifiers and reconcile the application state before opening a\n> replacement checkout.\n\n## Before checkout\n\n1. Select the intended organization before opening Billing. Do not rely on the\n organization that happened to be active in a previous browser session.\n2. Confirm the product, price, currency, interval, quantity, tax display, trial\n terms and expected access against the approval.\n3. Check whether the displayed promotion applies to this exact product and\n price. Visibility of a promotion does not guarantee that every item accepts it.\n4. Record the approver, expected effective date and application action that will\n prove the resulting access.\n5. Continue once to the hosted checkout presented by the application.\n\nPayment details, billing address and tax identifiers belong on that hosted\nbilling surface. Do not send them through application support, an API metadata\nfield or a screenshot.\n\nWhen you enter a promotion code, stop if checkout refuses it. Do not compensate\nby changing quantity, selecting another organization or asking support to copy\nthe discount manually. Recheck the product, validity period, redemption limit\nand discount currency against the approved offer.\n\n~~~mermaid\nsequenceDiagram\n accTitle: Start and verify a subscription\n accDescr: The administrator opens checkout from the application, completes provider-hosted payment, returns to the application, then verifies the application subscription and resulting access instead of trusting the redirect alone.\n participant A as Administrator\n participant App as Application\n participant B as Hosted billing\n A->>App: Select product and price for the intended scope\n App-->>A: Open authorized checkout\n A->>B: Confirm payment and billing details\n B-->>A: Return to application\n App->>App: Verify billing result and update subscription\n A->>App: Read subscription state and expected access\n~~~\n\nThe browser return is only navigation. The application updates its billing\nrecords from the verified provider result, then recomputes access. Closing the\nbrowser, losing the redirect or receiving a timeout does not establish whether\nthe provider completed the checkout.\n\nIf the hosted screen identifies itself as Stripe, see Stripe's maintained\n[subscription Checkout journey](https://docs.stripe.com/billing/subscriptions/build-subscriptions)\nfor the provider-side steps. That reference explains the hosted screen; the\napplication subscription and resulting access remain the completion evidence.\n\n## Confirm success\n\nDo not use the success URL as the success criterion. In the application, verify:\n\n- a subscription exists for the intended billing account;\n- its product, price and period are correct;\n- its state is **Active** or **Trialing**;\n- the expected feature or limit is available in the intended organization;\n- any first invoice has the expected total and state.\n\nUse the maintained subscription meanings when reading the result:\n\nThe subscription states and what each one means for access are listed under\n[Reconcile access after a billing change](/billing-and-subscriptions/reconcile-access).\n\nIf the state remains incomplete, past due, unpaid or absent, do not create a\nsecond checkout immediately. Use the troubleshooting and reconciliation pages\nto determine whether the first attempt is still being processed.\n\n### Example: the browser closes after payment\n\nSuppose an administrator approves a paid plan, completes the hosted\npayment, and the browser closes before returning. Reopen Billing in the same\norganization and read the current subscription. If the approved plan is Active\nand the expected limit works, record that result and close the task. If the\nsubscription is absent or Incomplete, preserve the first checkout identifier and\nreconcile it; **do not start another purchase merely to obtain a success page**.\n\n## Verify access, not only billing\n\nRepeat the application action identified before checkout. Confirm it in the\nsame organization and with an ordinary intended user—not only with the billing\nadministrator. Also verify one limit or unavailable action that should remain\nunchanged, so the proof does not hide an unexpectedly broad grant.\n\n## Retain safe completion evidence\n\nKeep the organization, product/price identity, checkout or subscription\nidentifier, visible status, period dates, first-invoice summary, approver,\ncorrelation data and access-verification result. Do not retain card details,\npayment-method data, complete invoice documents, provider secrets or the full\ncheckout URL.";
274
274
  }, {
275
275
  readonly managedPath: "billing-and-subscriptions/change-or-end-subscription.md";
276
276
  readonly unitRef: "technical-documentation:unit/change-or-end-billing-subscription";
277
277
  readonly sourceRefs: readonly ["saas-technical-doc:engine-content/change-or-end-billing-subscription", "source:consumer-fact:billing-lifecycle"];
278
- readonly markdown: "# Change, resume or end a subscription\n\nA plan change is both a commercial decision and an access decision. Before\nconfirming it, review the new price, effective date, prorated charge or credit,\nand the features or limits that will be added or removed.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Have the current subscription, approved target product/add-on, desired effective timing, expected charge or credit, and named access consequences | The application subscription reflects the approved change, access changes at the intended time, and no scheduled cancellation or stale item remains unexplained |\n\n{{CONSUMER_FACT:source:consumer-fact:billing-lifecycle#changeTimingMarkdown}}\n\n> **A requested policy is not proof of the applied charge or date.** Some billing\n> providers cannot schedule every change. Review any preview the application\n> presents, then verify the returned subscription, invoice or credit and the\n> resulting access. If those disagree with the approval, stop and reconcile the\n> change instead of applying another one.\n\n## Choose the lifecycle action\n\n~~~mermaid\nflowchart TD\n accTitle: Choose how a subscription should change\n accDescr: An administrator decides whether the organization needs a different base plan, an add-on change, end-of-period cancellation, immediate cancellation or reversal of a still-pending cancellation, then verifies the returned subscription and access consequence.\n need{\"What business decision was approved?\"}\n need -->|Replace base offer| plan[\"Change plan with product policy timing\"]\n need -->|Add or remove capacity| addon[\"Change subscription add-on\"]\n need -->|Stop at renewal| period[\"Schedule cancellation at period end\"]\n need -->|Stop now| immediate[\"Cancel immediately if policy permits\"]\n need -->|Undo pending cancellation| resume[\"Resume before the subscription ends\"]\n plan --> verify[\"Re-read subscription, charge evidence and access\"]\n addon --> verify\n period --> verify\n immediate --> verify\n resume --> verify\n~~~\n\nDo not choose from the wording “upgrade” or “downgrade” alone. Determine which\nbase product and add-ons will remain, when the provider applies the commercial\nchange, and when users should gain or lose the corresponding application access.\n\n## Change the plan or its add-ons\n\n1. Read the current subscription, including its items, state and period end.\n2. Choose the new plan or add-on from the current application catalogue.\n3. Confirm that the selected price belongs to that product and applies to the\n billed scope.\n4. Review the presented timing and proration before approving the change.\n5. After confirmation, re-read the subscription and verify the expected access.\n\nFor an add-on change, verify the base plan remains present and the intended\nadd-on appears or disappears exactly once. For a plan replacement, verify that\nthe returned base item is the approved product and price. Do not infer the\nresult from a checkout or portal confirmation message.\n\nDo not assume every billing connector can defer a downgrade. The **returned\napplication subscription** is the source of truth for what was applied.\n\nIf the hosted billing provider is Stripe, use its maintained\n[proration explanation](https://docs.stripe.com/billing/subscriptions/prorations)\nto interpret provider invoice lines. In particular, a credit line is not by\nitself proof that money was refunded, and a positive proration is not by itself\nproof that it was collected immediately. Match the application change, invoice\nstate and payment evidence.\n\n### Worked example: increase capacity mid-period\n\nAn organization has a 50-run plan and needs 20 additional runs immediately.\nBefore confirming an add-on, record:\n\n- the current 50-run limit and current billing-period end;\n- the add-on price and whether the presented adjustment is immediate;\n- the expected resolved limit of 70;\n- the application operation that will prove the extra capacity.\n\nAfter confirmation, verify that the base plan is still present, the add-on\nappears once, any provider adjustment matches the presented currency and period,\nand the resolved limit is 70. If the request times out, re-read those records\nbefore trying to add the same item again.\n\n## End at period end or cancel immediately\n\n- **End at period end** keeps the subscription active through its current\n period and marks it for cancellation. Access normally continues while the\n subscription remains Active or Trialing.\n- **Cancel immediately** marks the subscription Cancelled now and removes its\n contribution to billing-derived access when access is recomputed.\n\nImmediate cancellation is not always allowed by the product policy. Use it only\nwhen the business decision includes the immediate access consequence.\n\nBefore immediate cancellation, identify workflows, exports or administrative\nactions that depend on billing-derived access. Do not use a temporary manual\nrole or feature override to disguise the resulting loss; if continuity is\nrequired, approve the alternative access source explicitly.\n\n## Resume a scheduled cancellation\n\nA subscription can be resumed only while it is pending end-of-period\ncancellation. Resume clears that pending cancellation and returns the local\nsubscription to Active. Verify both the next period date and the resulting\naccess; a subscription that already ended needs a new approved purchase rather\nthan resume.\n\n## Verify by action and by time\n\n1. Confirm the returned subscription items, state, period end and cancellation\n flag in the billed scope.\n2. Match any immediate invoice or credit to the selected currency, quantity,\n proration and period.\n3. Repeat the application action affected by the change.\n4. For a deferred change, record what stays active now and schedule a check at\n the effective boundary.\n5. Verify an expected unaffected capability so the change did not alter a\n broader scope.\n\nRetain the approval, old and new product/price identities, selected timing,\nvisible proration evidence, subscription state and access proof. If the request\ntimes out, read the subscription before repeating it; an absent response is not\nevidence that the change failed.";
278
+ readonly markdown: "# Change, resume or end a subscription\n\nA plan change is both a commercial decision and an access decision. Before\nconfirming it, review the new price, effective date, prorated charge or credit,\nand the features or limits that will be added or removed.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Have the current subscription, approved target product/add-on, desired effective timing, expected charge or credit, and named access consequences | The application subscription reflects the approved change, access changes at the intended time, and no scheduled cancellation or stale item remains unexplained |\n\n{{CONSUMER_FACT:source:consumer-fact:billing-lifecycle#changeTimingMarkdown}}\n\n> **A requested policy is not proof of the applied charge or date.** Some billing\n> providers cannot schedule every change. Review any preview the application\n> presents, then verify the returned subscription, invoice or credit and the\n> resulting access. If those disagree with the approval, stop and reconcile the\n> change instead of applying another one.\n\n## Choose the lifecycle action\n\n~~~mermaid\nflowchart TD\n accTitle: Choose how a subscription should change\n accDescr: An administrator decides whether the organization needs a different base plan, an add-on change, end-of-period cancellation, immediate cancellation or reversal of a still-pending cancellation, then verifies the returned subscription and access consequence.\n need{\"What business decision was approved?\"}\n need -->|Replace base offer| plan[\"Change plan with product policy timing\"]\n need -->|Add or remove capacity| addon[\"Change subscription add-on\"]\n need -->|Stop at renewal| period[\"Schedule cancellation at period end\"]\n need -->|Stop now| immediate[\"Cancel immediately if policy permits\"]\n need -->|Undo pending cancellation| resume[\"Resume before the subscription ends\"]\n plan --> verify[\"Re-read subscription, charge evidence and access\"]\n addon --> verify\n period --> verify\n immediate --> verify\n resume --> verify\n~~~\n\nDo not choose from the wording “upgrade” or “downgrade” alone. Determine which\nbase product and add-ons will remain, when the provider applies the commercial\nchange, and when users should gain or lose the corresponding application access.\n\n## Change the plan or its add-ons\n\n1. Read the current subscription, including its items, state and period end.\n2. Choose the new plan or add-on from the current application catalogue.\n3. Confirm that the selected price belongs to that product and applies to the\n billed scope.\n4. Review the presented timing and proration before approving the change.\n5. After confirmation, re-read the subscription and verify the expected access.\n\nFor an add-on change, verify the base plan remains present and the intended\nadd-on appears or disappears exactly once. For a plan replacement, verify that\nthe returned base item is the approved product and price. Do not infer the\nresult from a checkout or portal confirmation message.\n\nDo not assume every billing connector can defer a downgrade. The **returned\napplication subscription** is the source of truth for what was applied.\n\nIf the hosted billing provider is Stripe, use its maintained\n[proration explanation](https://docs.stripe.com/billing/subscriptions/prorations)\nto interpret provider invoice lines. In particular, a credit line is not by\nitself proof that money was refunded, and a positive proration is not by itself\nproof that it was collected immediately. Match the application change, invoice\nstate and payment evidence.\n\n### Worked example: increase capacity mid-period\n\nThe figures below are illustrative; your own limits are shown in Billing.\nSuppose an organization's plan allows 50 automated runs and it needs 20 more\nimmediately. Before confirming an add-on, record:\n\n- the current 50-run limit and current billing-period end;\n- the add-on price and whether the presented adjustment is immediate;\n- the expected resolved limit of 70;\n- the application operation that will prove the extra capacity.\n\nAfter confirmation, verify that the base plan is still present, the add-on\nappears once, any provider adjustment matches the presented currency and period,\nand the resolved limit is 70. If the request times out, re-read those records\nbefore trying to add the same item again.\n\n## End at period end or cancel immediately\n\n- **End at period end** keeps the subscription active through its current\n period and marks it for cancellation. Access normally continues while the\n subscription remains Active or Trialing.\n- **Cancel immediately** marks the subscription Cancelled now and removes its\n contribution to billing-derived access when access is recomputed.\n\nImmediate cancellation is not always allowed by the product policy. Use it only\nwhen the business decision includes the immediate access consequence.\n\nBefore immediate cancellation, identify workflows, exports or administrative\nactions that depend on billing-derived access. Do not use a temporary manual\nrole or feature override to disguise the resulting loss; if continuity is\nrequired, approve the alternative access source explicitly.\n\n## Resume a scheduled cancellation\n\nA subscription can be resumed only while it is pending end-of-period\ncancellation. Resume clears that pending cancellation and returns the local\nsubscription to Active. Verify both the next period date and the resulting\naccess; a subscription that already ended needs a new approved purchase rather\nthan resume.\n\n## Verify by action and by time\n\n1. Confirm the returned subscription items, state, period end and cancellation\n flag in the billed scope.\n2. Match any immediate invoice or credit to the selected currency, quantity,\n proration and period.\n3. Repeat the application action affected by the change.\n4. For a deferred change, record what stays active now and schedule a check at\n the effective boundary.\n5. Verify an expected unaffected capability so the change did not alter a\n broader scope.\n\nRetain the approval, old and new product/price identities, selected timing,\nvisible proration evidence, subscription state and access proof. If the request\ntimes out, read the subscription before repeating it; an absent response is not\nevidence that the change failed.";
279
279
  }, {
280
280
  readonly managedPath: "billing-and-subscriptions/billing-records.md";
281
281
  readonly unitRef: "technical-documentation:unit/billing-records-and-usage";
@@ -290,7 +290,7 @@ export declare const APPLICATION_CONSUMER_DOCUMENTATION_AUTHORED_CONTENT_V1: rea
290
290
  readonly managedPath: "billing-and-subscriptions/metered-usage.md";
291
291
  readonly unitRef: "technical-documentation:unit/understand-metered-usage";
292
292
  readonly sourceRefs: readonly ["saas-technical-doc:engine-content/understand-metered-usage", "source:consumer-fact:billing-lifecycle"];
293
- readonly markdown: "# Understand metered usage\n\nA metered product charges for a measured quantity, such as processed documents,\nautomated runs or storage consumed. The application records the activity first;\nthe billing provider receives grouped usage later and uses its configured meter\nwhen preparing the invoice.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Know the organization, metered product, billing period, unit being counted and application action that produces it | Local records, reported state, provider quantity and invoice use the same product, scope, period and unit without duplicating usage |\n\n## Follow one quantity through the system\n\n~~~mermaid\nsequenceDiagram\n accTitle: Follow metered usage from application activity to an invoice\n accDescr: A successful application action creates a local usage row. The Billing area can show the local total while the row is pending. A scheduled flush groups pending rows by billing account and product, reports the quantity to the provider, then marks the local rows as reported. Provider processing is asynchronous, so the invoice can lag behind the newest local activity.\n participant U as User or workload\n participant App as Application\n participant Store as Local usage records\n participant Job as Billing reporter\n participant P as Billing provider\n U->>App: Complete a metered action\n App->>Store: Record product, quantity and occurrence time\n Note over Store: reportedToProvider = false\n Job->>Store: Read pending rows by account + product\n Job->>P: Report grouped quantity\n P-->>Job: Accept report\n Job->>Store: Mark included rows as reported\n P->>P: Process meter and prepare invoice asynchronously\n~~~\n\nThe two delays in the diagram are different:\n\n- **Pending locally** means the application has recorded the activity but has\n not yet marked it as reported to the provider.\n- **Accepted by the provider** still does not mean an invoice or provider usage\n summary has updated immediately. Provider meter processing is asynchronous.\n\nThe application does not promise a universal flush interval. Record the last\nlocal occurrence time and the reported state instead of saying “billing updates\nevery hour”.\n\n## Understand what created the record\n\n{{CONSUMER_FACT:source:consumer-fact:billing-lifecycle#usageSourceTypesMarkdown}}\n\nThe source helps an administrator locate the business action that produced the\nquantity. It is not a reason to store a person's name, email or free-text notes\nin usage metadata. These records are retained as financial history.\n\n## Worked example: local usage is temporarily ahead\n\nThree application actions create quantities of 40, 25 and 10 for the same\nproduct and billing period. The local total is **75**. The first two rows have\nalready been reported, while the last row remains pending, so the provider can\ntemporarily show **65**.\n\nDo not manually send the missing 10 or recreate the application action. First\nwait for the normal reporting boundary and verify that the original row becomes\nreported. Re-sending a quantity that the normal flush later sends can create a\nduplicate charge.\n\n## Reconcile a usage difference\n\n| Check | What to compare | What it rules out |\n| --- | --- | --- |\n| Scope | Environment, organization and billing account | Usage from another tenant or test environment |\n| Product | Product key and the unit described by the offer | Comparing requests with storage, seats or another meter |\n| Period | Local occurrence timestamps and provider invoice period | Correct usage assigned to a different billing cycle |\n| Local total | Every row in the period, including pending rows | A dashboard total that omitted recent activity |\n| Reporting state | **Reported to provider** and **reported at** values | Treating pending activity as already invoiced |\n| Provider result | Meter quantity and invoice state after processing | A provider-side delay or rejected meter event |\n\nClose the investigation only when the same records explain both totals, or when\na named correction owner has accepted the difference. Preserve the product,\nperiod, local total, reported total, pending row identifiers and correlation\nevidence. Do not retain provider credentials or personal data.\n\nIf the hosted provider is Stripe, its maintained\n[usage-based billing overview](https://docs.stripe.com/billing/subscriptions/usage-based/how-it-works),\n[meter-event recording guide](https://docs.stripe.com/billing/subscriptions/usage-based/recording-usage-api)\nand [meter configuration guide](https://docs.stripe.com/billing/subscriptions/usage-based/meters/configure)\nexplain the provider side. Use those references to interpret provider processing;\nuse the application's local records to identify what was actually measured.";
293
+ readonly markdown: "# Understand metered usage\n\nThis page applies only if a plan or add-on you hold charges for a measured\nquantity. If everything you subscribe to is a flat recurring price, no usage is\nrecorded and no usage line appears on an invoice — check\n[Understand plans, prices and access](/billing-and-subscriptions/plans-and-access)\nto see which of the two you have.\n\nA metered product charges for a measured quantity, such as processed documents,\nautomated runs or storage consumed. The application records the activity first;\nthe billing provider receives grouped usage later and uses its configured meter\nwhen preparing the invoice.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Know the organization, metered product, billing period, unit being counted and application action that produces it | Local records, reported state, provider quantity and invoice use the same product, scope, period and unit without duplicating usage |\n\n## Follow one quantity through the system\n\n~~~mermaid\nsequenceDiagram\n accTitle: Follow metered usage from application activity to an invoice\n accDescr: A successful application action creates a local usage row. The Billing area can show the local total while the row is pending. A scheduled flush groups pending rows by billing account and product, reports the quantity to the provider, then marks the local rows as reported. Provider processing is asynchronous, so the invoice can lag behind the newest local activity.\n participant U as User or workload\n participant App as Application\n participant Store as Local usage records\n participant Job as Billing reporter\n participant P as Billing provider\n U->>App: Complete a metered action\n App->>Store: Record product, quantity and occurrence time\n Note over Store: reportedToProvider = false\n Job->>Store: Read pending rows by account + product\n Job->>P: Report grouped quantity\n P-->>Job: Accept report\n Job->>Store: Mark included rows as reported\n P->>P: Process meter and prepare invoice asynchronously\n~~~\n\nThe two delays in the diagram are different:\n\n- **Pending locally** means the application has recorded the activity but has\n not yet marked it as reported to the provider.\n- **Accepted by the provider** still does not mean an invoice or provider usage\n summary has updated immediately. Provider meter processing is asynchronous.\n\nThe application does not promise a universal flush interval. Record the last\nlocal occurrence time and the reported state instead of saying “billing updates\nevery hour”.\n\n## Understand what created the record\n\n{{CONSUMER_FACT:source:consumer-fact:billing-lifecycle#usageSourceTypesMarkdown}}\n\nThe source helps an administrator locate the business action that produced the\nquantity. It is not a reason to store a person's name, email or free-text notes\nin usage metadata. These records are retained as financial history.\n\n## Worked example: local usage is temporarily ahead\n\nThree application actions create quantities of 40, 25 and 10 for the same\nproduct and billing period. The local total is **75**. The first two rows have\nalready been reported, while the last row remains pending, so the provider can\ntemporarily show **65**.\n\nDo not manually send the missing 10 or recreate the application action. First\nwait for the normal reporting boundary and verify that the original row becomes\nreported. Re-sending a quantity that the normal flush later sends can create a\nduplicate charge.\n\n## Reconcile a usage difference\n\n| Check | What to compare | What it rules out |\n| --- | --- | --- |\n| Scope | Environment, organization and billing account | Usage from another tenant or test environment |\n| Product | Product key and the unit described by the offer | Comparing requests with storage, seats or another meter |\n| Period | Local occurrence timestamps and provider invoice period | Correct usage assigned to a different billing cycle |\n| Local total | Every row in the period, including pending rows | A dashboard total that omitted recent activity |\n| Reporting state | **Reported to provider** and **reported at** values | Treating pending activity as already invoiced |\n| Provider result | Meter quantity and invoice state after processing | A provider-side delay or rejected meter event |\n\nClose the investigation only when the same records explain both totals, or when\na named correction owner has accepted the difference. Preserve the product,\nperiod, local total, reported total, pending row identifiers and correlation\nevidence. Do not retain provider credentials or personal data.\n\nIf the hosted provider is Stripe, its maintained\n[usage-based billing overview](https://docs.stripe.com/billing/subscriptions/usage-based/how-it-works),\n[meter-event recording guide](https://docs.stripe.com/billing/subscriptions/usage-based/recording-usage-api)\nand [meter configuration guide](https://docs.stripe.com/billing/subscriptions/usage-based/meters/configure)\nexplain the provider side. Use those references to interpret provider processing;\nuse the application's local records to identify what was actually measured.";
294
294
  }, {
295
295
  readonly managedPath: "billing-and-subscriptions/reconcile-access.md";
296
296
  readonly unitRef: "technical-documentation:unit/reconcile-billing-and-access";
@@ -299,8 +299,8 @@ export declare const APPLICATION_CONSUMER_DOCUMENTATION_AUTHORED_CONTENT_V1: rea
299
299
  }, {
300
300
  readonly managedPath: "billing-and-subscriptions/troubleshoot.md";
301
301
  readonly unitRef: "technical-documentation:unit/troubleshoot-billing-change";
302
- readonly sourceRefs: readonly ["saas-technical-doc:engine-content/troubleshoot-billing-change", "source:consumer-fact:billing-lifecycle"];
303
- readonly markdown: "# Troubleshoot a billing change\n\nBegin with what the administrator or user can observe. Repeating checkout,\ngranting a broader role or manually changing access before identifying the\nfailed layer can create duplicate charges or hide the original problem.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Preserve the environment, organization, first attempt, product/price, subscription or invoice identifier, approximate time, visible status and original application symptom | One failing boundary is identified and repaired without duplicating a purchase, exposing payment data or leaving unrelated access in place |\n\n## Diagnose from the first durable record\n\n~~~mermaid\nflowchart TD\n accTitle: Troubleshoot a billing change without repeating it blindly\n accDescr: The administrator starts from the first checkout or subscription evidence, confirms the billed scope, reads current subscription and invoice state, compares product grants with resolved access, then repeats the original application action after repairing only the failing layer.\n symptom[\"Billing or access result is unexpected\"] --> scope[\"Confirm environment and billed scope\"]\n scope --> attempt[\"Preserve first checkout or change evidence\"]\n attempt --> subscription{\"Application subscription present?\"}\n subscription -->|No or incomplete| payment[\"Check invoice/provider evidence and processing state\"]\n subscription -->|Yes| status{\"State contributes billing access?\"}\n status -->|No| payment\n status -->|Yes| grants[\"Compare product/add-on grants with resolved access\"]\n grants --> action[\"Repeat original application action\"]\n payment --> repair[\"Repair payment or reconcile verified provider result\"]\n repair --> subscription\n~~~\n\nDo not begin from a success redirect, provider email or plan label. Begin from\nthe application billing account and current subscription for the intended\nscope, then correlate provider evidence only where the state requires it.\n\nUse these maintained state meanings while diagnosing:\n\n{{CONSUMER_FACT:source:consumer-fact:billing-lifecycle#subscriptionStatusesMarkdown}}\n\n## Start from the symptom\n\n| Symptom | First checks | Safe next step |\n| --- | --- | --- |\n| Returned from checkout but no subscription appears | Intended scope, existing incomplete subscription, processing delay and the first attempt's billing evidence | Reconcile the first attempt before opening checkout again |\n| Subscription is Active but feature is unavailable | Product and price, expected grants, current organization, resolved feature/limit and the original operation | Repair grant/access reconciliation; do not broaden the person's role |\n| Subscription is Past due, Unpaid or Paused | Current invoice state and the authenticated billing portal; these states do not contribute billing-derived access | Resolve payment in the portal, then wait for verified application state |\n| Downgrade or cancellation appears immediate | Returned subscription items, status, period end and cancellation flag; do not rely only on the requested timing | Compare the applied product policy and access consequence with the approval |\n| Cancellation was requested but access remains | End-of-period cancellation may intentionally keep an Active subscription until period end | Record the effective boundary and verify again when the period ends |\n| Invoice total differs from expectation | Currency, tax display, quantity, proration, promotion and billing period | Compare the selected offer and applied adjustment before disputing the charge |\n| Metered usage differs from provider | Local period total, last recorded time, reported state and aggregation delay | Wait for the bounded reporting window, then compare the same product and period |\n| Resume is refused | The subscription must still be pending end-of-period cancellation | If it already ended, use a newly approved purchase instead of resume |\n| Billing screen is correct but the application action fails | Resolved feature/limit, organization, role and exact operation | Troubleshoot authorization or resource scope separately from billing |\n\n## Recover without making the record harder to understand\n\n- Keep the first checkout or change identifiers and do not create a replacement\n until its state is known.\n- Use the authenticated billing portal for payment methods and invoice documents.\n- Correct the product, price or scope through the normal billing operation; do\n not patch subscription status directly.\n- After recovery, verify both the billing record and the application action that\n depends on it.\n- Share invoice identifiers, status, timestamps and correlation evidence with\n support—not card details, full invoice documents or provider secrets.\n\nIf the application record and provider evidence still disagree, preserve both\nviews and escalate the reconciliation. The application retains subscriptions,\ninvoice references and usage records as financial history rather than deleting\nthem when a scope is retired.\n\n## Escalate a reproducible case\n\nProvide the environment, billed organization, product/price identity, first\nattempt or subscription identifier, invoice summary, timestamps, current state,\nexpected access, observed application action and correlation identifier. State\nwhether payment, subscription state or access changed between observations.\nNever attach card data, payment-method details, complete invoice documents,\nhosted invoice URLs, provider secrets or unrestricted personal data.";
302
+ readonly sourceRefs: readonly ["saas-technical-doc:engine-content/troubleshoot-billing-change"];
303
+ readonly markdown: "# Troubleshoot a billing change\n\nBegin with what the administrator or user can observe. Repeating checkout,\ngranting a broader role or manually changing access before identifying the\nfailed layer can create duplicate charges or hide the original problem.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Preserve the environment, organization, first attempt, product/price, subscription or invoice identifier, approximate time, visible status and original application symptom | One failing boundary is identified and repaired without duplicating a purchase, exposing payment data or leaving unrelated access in place |\n\n## Diagnose from the first durable record\n\n~~~mermaid\nflowchart TD\n accTitle: Troubleshoot a billing change without repeating it blindly\n accDescr: The administrator starts from the first checkout or subscription evidence, confirms the billed scope, reads current subscription and invoice state, compares product grants with resolved access, then repeats the original application action after repairing only the failing layer.\n symptom[\"Billing or access result is unexpected\"] --> scope[\"Confirm environment and billed scope\"]\n scope --> attempt[\"Preserve first checkout or change evidence\"]\n attempt --> subscription{\"Application subscription present?\"}\n subscription -->|No or incomplete| payment[\"Check invoice/provider evidence and processing state\"]\n subscription -->|Yes| status{\"State contributes billing access?\"}\n status -->|No| payment\n status -->|Yes| grants[\"Compare product/add-on grants with resolved access\"]\n grants --> action[\"Repeat original application action\"]\n payment --> repair[\"Repair payment or reconcile verified provider result\"]\n repair --> subscription\n~~~\n\nDo not begin from a success redirect, provider email or plan label. Begin from\nthe application billing account and current subscription for the intended\nscope, then correlate provider evidence only where the state requires it.\n\nUse these maintained state meanings while diagnosing:\n\nThe full list of subscription states, and what each one means for access, is under\n[Reconcile access after a billing change](/billing-and-subscriptions/reconcile-access).\n\n## Start from the symptom\n\n| Symptom | First checks | Safe next step |\n| --- | --- | --- |\n| Returned from checkout but no subscription appears | Intended scope, existing incomplete subscription, processing delay and the first attempt's billing evidence | Reconcile the first attempt before opening checkout again |\n| Subscription is Active but feature is unavailable | Product and price, expected grants, current organization, resolved feature/limit and the original operation | Repair grant/access reconciliation; do not broaden the person's role |\n| Subscription is Past due, Unpaid or Paused | Current invoice state and the authenticated billing portal; these states do not contribute billing-derived access | Resolve payment in the portal, then wait for verified application state |\n| Downgrade or cancellation appears immediate | Returned subscription items, status, period end and cancellation flag; do not rely only on the requested timing | Compare the applied product policy and access consequence with the approval |\n| Cancellation was requested but access remains | End-of-period cancellation may intentionally keep an Active subscription until period end | Record the effective boundary and verify again when the period ends |\n| Invoice total differs from expectation | Currency, tax display, quantity, proration, promotion and billing period | Compare the selected offer and applied adjustment before disputing the charge |\n| Metered usage differs from provider | Local period total, last recorded time, reported state and aggregation delay | Wait for the bounded reporting window, then compare the same product and period |\n| Resume is refused | The subscription must still be pending end-of-period cancellation | If it already ended, use a newly approved purchase instead of resume |\n| Billing screen is correct but the application action fails | Resolved feature/limit, organization, role and exact operation | Troubleshoot authorization or resource scope separately from billing |\n\n## Recover without making the record harder to understand\n\n- Keep the first checkout or change identifiers and do not create a replacement\n until its state is known.\n- Use the authenticated billing portal for payment methods and invoice documents.\n- Correct the product, price or scope through the normal billing operation; do\n not patch subscription status directly.\n- After recovery, verify both the billing record and the application action that\n depends on it.\n- Share invoice identifiers, status, timestamps and correlation evidence with\n support—not card details, full invoice documents or provider secrets.\n\nIf the application record and provider evidence still disagree, preserve both\nviews and escalate the reconciliation. The application retains subscriptions,\ninvoice references and usage records as financial history rather than deleting\nthem when a scope is retired.\n\n## Escalate a reproducible case\n\nProvide the environment, billed organization, product/price identity, first\nattempt or subscription identifier, invoice summary, timestamps, current state,\nexpected access, observed application action and correlation identifier. State\nwhether payment, subscription state or access changed between observations.\nNever attach card data, payment-method details, complete invoice documents,\nhosted invoice URLs, provider secrets or unrestricted personal data.";
304
304
  }, {
305
305
  readonly managedPath: "integrations.md";
306
306
  readonly unitRef: "technical-documentation:unit/integrations";
@@ -329,23 +329,23 @@ export declare const APPLICATION_CONSUMER_DOCUMENTATION_AUTHORED_CONTENT_V1: rea
329
329
  }, {
330
330
  readonly managedPath: "integrations/ai-coding-tools.md";
331
331
  readonly unitRef: "technical-documentation:unit/ai-coding-tools";
332
- readonly sourceRefs: readonly ["saas-technical-doc:engine-content/ai-coding-tools"];
333
- readonly markdown: "# AI coding tools\n\nThis application publishes an **MCP tool server** that supported AI coding\nclients can connect to. The client can discover only the tools admitted for the\nauthenticated identity. Connecting the server does not give the model universal\naccess, and it does not turn every application action into an autonomous one.\n\n## What you need from an administrator\n\n- the server origin for the intended application environment;\n- authorization to use the MCP audience at\n **<server-origin>/api/v1/mcp**;\n- membership and roles for the organization you intend to work in;\n- confirmation of which tools may run automatically and which require approval.\n\nUse OAuth sign-in when the client and application offer it. For unattended\nmachine access, use a separately registered client and an audience-bound access\ntoken; do not reuse an ordinary REST API key at the MCP endpoint.\n\n~~~mermaid\nsequenceDiagram\n accTitle: Connect an AI coding client without bypassing application access\n accDescr: The operator adds the application MCP URL, authenticates for that MCP audience, reviews the caller-specific tool catalogue, tests one read-only tool, and enables broader use only after approval and audit evidence are understood.\n participant Person\n participant Client as AI coding client\n participant App as Application MCP server\n Person->>Client: Add environment-specific MCP URL\n Client->>App: Discover authorization metadata\n Person->>App: Authenticate and authorize access\n Client->>App: List tools for this identity\n App-->>Client: Caller-specific catalogue\n Person->>Client: Approve one read-only test\n Client->>App: Call advertised tool\n App-->>Client: Result or structured refusal\n~~~\n\n## Choose your client\n\n- [Connect Cursor](/integrations/ai-tools/cursor) for a project or user-level\n MCP connection in Cursor.\n- [Connect Codex](/integrations/ai-tools/codex) for Codex CLI, the IDE extension\n or the ChatGPT desktop app on the same Codex host.\n- [Connect Claude Code](/integrations/ai-tools/claude-code) for a local, project\n or user-scoped remote HTTP connection.\n\n## Establish a safe default\n\nStart in a non-production organization. Keep tool approval enabled and invoke\none read-only tool whose expected result you can verify in the application. If\na tool is absent, treat that as an authorization result; do not guess its name\nor copy a catalogue from another person.\n\nBefore allowing mutations, decide how the team will review arguments, reconcile\ntimeouts, revoke access and investigate a disputed action. Prompts and client\ntranscripts are not the authoritative audit record, and credentials must never\nbe pasted into either.";
332
+ readonly sourceRefs: readonly ["saas-technical-doc:engine-content/ai-coding-tools", "source:companion-projection:application-connection"];
333
+ readonly markdown: "# AI coding tools\n\nThis application publishes an **MCP tool server** that supported AI coding\nclients can connect to. The client can discover only the tools admitted for the\nauthenticated identity. Connecting the server does not give the model universal\naccess, and it does not turn every application action into an autonomous one.\n\n## What you need from an administrator\n\n- the server origin for the intended application environment;\n- authorization to use the MCP audience at\n **{{APPLICATION_CONNECTION_VALUE:mcpEndpointUrl}}**;\n- membership and roles for the organization you intend to work in;\n- confirmation of which tools may run automatically and which require approval.\n\nUse OAuth sign-in when the client and application offer it. For unattended\nmachine access, use a separately registered client and an audience-bound access\ntoken; do not reuse an ordinary REST API key at the MCP endpoint.\n\n~~~mermaid\nsequenceDiagram\n accTitle: Connect an AI coding client without bypassing application access\n accDescr: The operator adds the application MCP URL, authenticates for that MCP audience, reviews the caller-specific tool catalogue, tests one read-only tool, and enables broader use only after approval and audit evidence are understood.\n participant Person\n participant Client as AI coding client\n participant App as Application MCP server\n Person->>Client: Add environment-specific MCP URL\n Client->>App: Discover authorization metadata\n Person->>App: Authenticate and authorize access\n Client->>App: List tools for this identity\n App-->>Client: Caller-specific catalogue\n Person->>Client: Approve one read-only test\n Client->>App: Call advertised tool\n App-->>Client: Result or structured refusal\n~~~\n\n## Choose your client\n\n- [Connect Cursor](/integrations/ai-tools/cursor) for a project or user-level\n MCP connection in Cursor.\n- [Connect Codex](/integrations/ai-tools/codex) for Codex CLI, the IDE extension\n or the ChatGPT desktop app on the same Codex host.\n- [Connect Claude Code](/integrations/ai-tools/claude-code) for a local, project\n or user-scoped remote HTTP connection.\n\n## Establish a safe default\n\nStart in a non-production organization. Keep tool approval enabled and invoke\none read-only tool whose expected result you can verify in the application. If\na tool is absent, treat that as an authorization result; do not guess its name\nor copy a catalogue from another person.\n\nBefore allowing mutations, decide how the team will review arguments, reconcile\ntimeouts, revoke access and investigate a disputed action. Prompts and client\ntranscripts are not the authoritative audit record, and credentials must never\nbe pasted into either.";
334
334
  }, {
335
335
  readonly managedPath: "integrations/ai-tools/cursor.md";
336
336
  readonly unitRef: "technical-documentation:unit/connect-cursor";
337
- readonly sourceRefs: readonly ["saas-technical-doc:engine-content/connect-cursor"];
338
- readonly markdown: "# Connect Cursor\n\nUse this guide when Cursor Agent should read or act on information in this\napplication without asking you to copy that information into a prompt. The\nconnection uses the application's remote MCP server. The server offers Cursor\nonly the tools available to the signed-in identity; connecting it does not grant\nnew application access.\n\nYou will add one environment-specific server, authenticate, inspect the tools\nCursor can actually see, and approve one read-only call whose result you can\nrecognize in the application.\n\n## Decide who should receive the connection\n\nChoose the configuration scope before creating a file:\n\n| The connection is for… | Configuration | Consequence |\n| --- | --- | --- |\n| Only you, across trusted projects | **~/.cursor/mcp.json** | The server is available in your own Cursor environment and is not committed with a project |\n| Everyone who opens one trusted project | **.cursor/mcp.json** in that project | The server declaration may be shared with the repository; every teammate must still authenticate as themselves |\n\nUse the project scope only when the team has approved the server origin and\npurpose. A shared declaration must never contain a personal token or client\nsecret.\n\n## Add the remote server\n\nCreate the selected **mcp.json** file and add:\n\n~~~json\n{\n \"mcpServers\": {\n \"application\": {\n \"url\": \"<server-origin>/api/v1/mcp\"\n }\n }\n}\n~~~\n\nReplace **<server-origin>** with the server origin for the intended application\nenvironment. Keep **/api/v1/mcp** exactly once. Do not add an Authorization\nheader to the shared JSON when the server supports interactive OAuth.\n\nCursor's [current MCP documentation](https://cursor.com/docs/mcp) owns the\nconfiguration locations, remote transport, OAuth and approval controls. If your\ninstalled version differs, follow its visible configuration location while\nkeeping the application URL and access boundary described here.\n\n## Connect and sign in\n\n1. Open **Cursor Settings → Customize → MCP** and find the server named\n **application**.\n2. Confirm that the displayed URL is the intended non-production environment.\n3. Enable the server if it is disabled.\n4. Complete the OAuth sign-in offered by Cursor. Sign in as yourself and select\n the organization approved for this test.\n5. Return to the MCP server and confirm it reports a connected state.\n\nThe authorization must be issued for this MCP server. A REST API key or a token\nfor another audience is not an interchangeable substitute.\n\n## Inspect before asking Cursor to act\n\nOpen the server's **Available Tools** list. Read the tool names and descriptions\nbefore using Agent. A shorter list than a colleague sees can be correct: the\napplication filters tools using the authenticated identity, active organization,\nroles and published operations.\n\nStart with a prompt that does not call a tool:\n\n> List the tools available from the **application** MCP server. Explain which\n> one you would use to read the known test record. **Do not call a tool yet.**\n\nCompare Cursor's proposal with the visible tool description. If it proposes a\ndifferent organization, a write operation or a tool that is not in the current\ncatalogue, correct the task before approval.\n\n## Prove one read-only task\n\nChoose a record or collection whose expected result you can see in the\napplication, then ask Cursor to perform that specific read. When Cursor displays\nthe tool approval:\n\n1. expand the tool call;\n2. confirm the tool name is from the **application** server;\n3. inspect every organization and resource identifier;\n4. refuse the call if any argument is broader than the task; and\n5. approve the call once.\n\nCompare the returned organization, record identity and material fields with the\napplication. A fluent answer is not verification—the application state is.\n\n~~~mermaid\nsequenceDiagram\n accTitle: Prove a Cursor MCP connection with one bounded read\n accDescr: A person adds an environment-specific server, signs in, reviews the caller-specific tool list, inspects one read-only call and compares the result with application state before considering broader use.\n actor Person\n participant Cursor\n participant App as Application MCP server\n Person->>Cursor: Add server and verify environment\n Cursor->>App: Initialize and request authentication\n Person->>App: Sign in for the intended organization\n Cursor->>App: List tools for this identity\n App-->>Cursor: Caller-specific catalogue\n Person->>Cursor: Approve one inspected read\n Cursor->>App: Call advertised tool\n App-->>Cursor: Result or structured refusal\n Person->>Person: Compare result with application state\n~~~\n\n## When the connection does not work\n\n| What Cursor shows | Check first | Safe next action |\n| --- | --- | --- |\n| Server is missing | The chosen mcp.json location and valid JSON | Correct the file, then reload Cursor; do not create a second configuration in another scope |\n| Server cannot connect | Environment origin, **/api/v1/mcp**, network and TLS | Correct the URL or reachability before changing authentication |\n| Sign-in repeats | Server environment and OAuth completion | Remove stale authorization for this server and sign in again to the intended environment |\n| Connected, but no tools | Active organization, membership, roles and published MCP operations | Ask the administrator to verify the intended access; do not copy another person's tool list |\n| Expected tool is absent | Current caller-specific catalogue | Use a published alternative or request the narrowly required role/operation |\n| Tool returns **403** | Tool arguments and operation authority | Treat it as an access decision; changing the prompt or enabling automatic execution cannot grant access |\n| Write result is unclear | Authoritative application record and audit evidence | Read current state before approving another call |\n\n## Before allowing state-changing tools\n\n- Keep Cursor's tool approval enabled and inspect every write argument.\n- Disable tools the project does not need.\n- Never commit a token, secret or another person's credential in **mcp.json**.\n- Treat tool descriptions, returned text and links as untrusted context that can\n influence the model.\n- Agree who investigates and reverses an unintended change.\n- Use the application's audit trail, not the conversation alone, when a\n protected action is disputed.\n- Use a dedicated machine identity for unattended automation rather than a\n person's interactive authorization.";
337
+ readonly sourceRefs: readonly ["saas-technical-doc:engine-content/connect-cursor", "source:companion-projection:application-connection"];
338
+ readonly markdown: "# Connect Cursor\n\nUse this guide when Cursor Agent should read or act on information in this\napplication without asking you to copy that information into a prompt. The\nconnection uses the application's remote MCP server. The server offers Cursor\nonly the tools available to the signed-in identity; connecting it does not grant\nnew application access.\n\nYou will add one environment-specific server, authenticate, inspect the tools\nCursor can actually see, and approve one read-only call whose result you can\nrecognize in the application.\n\n## Decide who should receive the connection\n\nChoose the configuration scope before creating a file:\n\n| The connection is for… | Configuration | Consequence |\n| --- | --- | --- |\n| Only you, across trusted projects | **~/.cursor/mcp.json** | The server is available in your own Cursor environment and is not committed with a project |\n| Everyone who opens one trusted project | **.cursor/mcp.json** in that project | The server declaration may be shared with the repository; every teammate must still authenticate as themselves |\n\nUse the project scope only when the team has approved the server origin and\npurpose. A shared declaration must never contain a personal token or client\nsecret.\n\n## Add the remote server\n\nCreate the selected **mcp.json** file and add:\n\n~~~json\n{\n \"mcpServers\": {\n \"application\": {\n \"url\": \"{{APPLICATION_CONNECTION_VALUE:mcpEndpointUrl}}\"\n }\n }\n}\n~~~\n\nThe URL above is this application’s MCP endpoint. Confirm it belongs to the environment you intend before connecting. Keep **/api/v1/mcp** exactly once. Do not add an Authorization\nheader to the shared JSON when the server supports interactive OAuth.\n\nCursor's [current MCP documentation](https://cursor.com/docs/mcp) owns the\nconfiguration locations, remote transport, OAuth and approval controls. If your\ninstalled version differs, follow its visible configuration location while\nkeeping the application URL and access boundary described here.\n\n## Connect and sign in\n\n1. Open **Cursor Settings → Customize → MCP** and find the server named\n **application**.\n2. Confirm that the displayed URL is the intended non-production environment.\n3. Enable the server if it is disabled.\n4. Complete the OAuth sign-in offered by Cursor. Sign in as yourself and select\n the organization approved for this test.\n5. Return to the MCP server and confirm it reports a connected state.\n\nThe authorization must be issued for this MCP server. A REST API key or a token\nfor another audience is not an interchangeable substitute.\n\n## Inspect before asking Cursor to act\n\nOpen the server's **Available Tools** list. Read the tool names and descriptions\nbefore using Agent. A shorter list than a colleague sees can be correct: the\napplication filters tools using the authenticated identity, active organization,\nroles and published operations.\n\nStart with a prompt that does not call a tool:\n\n> List the tools available from the **application** MCP server. Explain which\n> one you would use to read the known test record. **Do not call a tool yet.**\n\nCompare Cursor's proposal with the visible tool description. If it proposes a\ndifferent organization, a write operation or a tool that is not in the current\ncatalogue, correct the task before approval.\n\n## Prove one read-only task\n\nChoose a record or collection whose expected result you can see in the\napplication, then ask Cursor to perform that specific read. When Cursor displays\nthe tool approval:\n\n1. expand the tool call;\n2. confirm the tool name is from the **application** server;\n3. inspect every organization and resource identifier;\n4. refuse the call if any argument is broader than the task; and\n5. approve the call once.\n\nCompare the returned organization, record identity and material fields with the\napplication. A fluent answer is not verification—the application state is.\n\n~~~mermaid\nsequenceDiagram\n accTitle: Prove a Cursor MCP connection with one bounded read\n accDescr: A person adds an environment-specific server, signs in, reviews the caller-specific tool list, inspects one read-only call and compares the result with application state before considering broader use.\n actor Person\n participant Cursor\n participant App as Application MCP server\n Person->>Cursor: Add server and verify environment\n Cursor->>App: Initialize and request authentication\n Person->>App: Sign in for the intended organization\n Cursor->>App: List tools for this identity\n App-->>Cursor: Caller-specific catalogue\n Person->>Cursor: Approve one inspected read\n Cursor->>App: Call advertised tool\n App-->>Cursor: Result or structured refusal\n Person->>Person: Compare result with application state\n~~~\n\n## When the connection does not work\n\n| What Cursor shows | Check first | Safe next action |\n| --- | --- | --- |\n| Server is missing | The chosen mcp.json location and valid JSON | Correct the file, then reload Cursor; do not create a second configuration in another scope |\n| Server cannot connect | Environment origin, **/api/v1/mcp**, network and TLS | Correct the URL or reachability before changing authentication |\n| Sign-in repeats | Server environment and OAuth completion | Remove stale authorization for this server and sign in again to the intended environment |\n| Connected, but no tools | Active organization, membership, roles and published MCP operations | Ask the administrator to verify the intended access; do not copy another person's tool list |\n| Expected tool is absent | Current caller-specific catalogue | Use a published alternative or request the narrowly required role/operation |\n| Tool returns **403** | Tool arguments and operation authority | Treat it as an access decision; changing the prompt or enabling automatic execution cannot grant access |\n| Write result is unclear | Authoritative application record and audit evidence | Read current state before approving another call |\n\n## Before allowing state-changing tools\n\n- Keep Cursor's tool approval enabled and inspect every write argument.\n- Disable tools the project does not need.\n- Never commit a token, secret or another person's credential in **mcp.json**.\n- Treat tool descriptions, returned text and links as untrusted context that can\n influence the model.\n- Agree who investigates and reverses an unintended change.\n- Use the application's audit trail, not the conversation alone, when a\n protected action is disputed.\n- Use a dedicated machine identity for unattended automation rather than a\n person's interactive authorization.";
339
339
  }, {
340
340
  readonly managedPath: "integrations/ai-tools/codex.md";
341
341
  readonly unitRef: "technical-documentation:unit/connect-codex";
342
- readonly sourceRefs: readonly ["saas-technical-doc:engine-content/connect-codex"];
343
- readonly markdown: "# Connect Codex\n\nUse this guide when Codex needs authorized information or operations from this\napplication while helping with a coding task. The connection uses the\napplication's remote MCP server. Codex receives only the tools available to the\nauthenticated identity; adding the server does not create a new role or bypass\norganization access.\n\nYou will register one server, authenticate, inspect the active tool catalogue,\napprove one read-only call and compare the result with the application.\n\n## Choose the configuration scope\n\nCodex CLI, the IDE extension and the ChatGPT desktop app share MCP configuration\non the same Codex host.\n\n| The server is for… | Configuration file | Use it when |\n| --- | --- | --- |\n| Your Codex environment | **~/.codex/config.toml** | You need the application across your own trusted workspaces |\n| One trusted project | **.codex/config.toml** in that project | The team has approved sharing the server declaration with the project |\n\nA project file may contain the server URL and approval policy. It must not\ncontain a personal bearer token or another person's credential.\n\n## Register the remote server\n\nAdd this table to the selected configuration file:\n\n~~~toml\n[mcp_servers.application]\nurl = \"<server-origin>/api/v1/mcp\"\ndefault_tools_approval_mode = \"prompt\"\n~~~\n\nReplace **<server-origin>** with the server origin of the intended application\nenvironment. Keep **/api/v1/mcp** exactly once. The prompt approval mode means\nCodex asks before using tools from this server.\n\nThe [official Codex MCP documentation](https://learn.chatgpt.com/docs/extend/mcp?surface=cli)\ndefines the current configuration keys, Streamable HTTP support, OAuth login\nand per-server tool controls.\n\n## Confirm registration and authenticate\n\nIn a terminal on the same host, run **codex mcp list**. The output should include\n**application** with the URL you configured. If it is missing, correct the file\nand scope before attempting authentication.\n\nStart the interactive OAuth flow:\n\n~~~bash\ncodex mcp login application\n~~~\n\nComplete sign-in for the intended non-production environment and organization.\nThen open Codex and use **/mcp**. Confirm that the **application** server is\nactive and inspect its tools.\n\n> **Keep credentials out of configuration and prompts.** Interactive users\n> should use the OAuth login. If an administrator deliberately provides a\n> machine token, store it in a protected environment variable and configure\n> only its variable name with **bearer_token_env_var**.\n\n## Inspect the tool before calling it\n\nStart by asking Codex to reason without executing:\n\n> From the **application** MCP server, identify the tool that can read the known\n> test record. Show the proposed tool name and arguments. **Do not call it.**\n\nCompare the proposed tool with the current **/mcp** catalogue. An empty or\nnarrower catalogue can be correct because the server filters tools for the\nsigned-in identity. Do not guess a missing tool name or paste another person's\ncatalogue into the prompt.\n\n## Prove one read-only call\n\nAsk Codex to call the selected read-only tool for one known organization and\nrecord. At the approval prompt:\n\n1. confirm the server is **application**;\n2. confirm the tool is marked or described as read-only;\n3. inspect organization and resource identifiers;\n4. refuse arguments that are broader than the task; and\n5. approve the call once.\n\nCompare the returned identity and material fields with current application\nstate. The conversation may summarize the result, but the application remains\nthe authoritative source.\n\n~~~mermaid\nflowchart TD\n accTitle: Verify a Codex MCP connection before allowing changes\n accDescr: The user registers the remote server, completes audience-specific authentication, inspects the active tools, approves one read-only call, and compares its result with the application before considering write access.\n config[\"Register remote MCP URL\"] --> auth[\"Complete MCP authentication\"]\n auth --> inspect[\"Inspect /mcp tool catalogue\"]\n inspect --> approve[\"Approve one read-only call\"]\n approve --> compare[\"Compare with application state\"]\n compare --> decision{\"Broader access justified?\"}\n decision -->|No| keep[\"Keep prompt approvals and narrow tools\"]\n decision -->|Yes| govern[\"Document write approvals and recovery\"]\n~~~\n\nThe decision at the end of the diagram is deliberately separate from\nconnectivity. A working read does not justify automatic write approval.\n\n## When Codex does not show the expected result\n\n| What you observe | Check first | Safe next action |\n| --- | --- | --- |\n| **application** absent from **codex mcp list** | Config file, TOML syntax and selected scope | Correct the one intended configuration; do not duplicate the server in user and project scope |\n| Server fails to initialize | URL, network, TLS and **/api/v1/mcp** | Repair reachability before changing roles or credentials |\n| OAuth login does not complete | Environment URL, browser sign-in and callback completion | Retry login for this server; never paste a token into the conversation |\n| Server active, no tools | Active organization, membership, roles and MCP publication | Ask the administrator to verify the intended access boundary |\n| Tool absent | The current **/mcp** catalogue | Use an admitted alternative or request only the required operation/role |\n| Tool returns **403** | Tool arguments and operation authority | Treat the response as an authorization decision; prompt wording cannot grant a role |\n| Write timed out | Application record and audit evidence | Read current state before approving any repeat |\n\n## Before enabling broader use\n\n- Keep the server pinned to one environment; never silently change a shared\n project from test to production.\n- Use **enabled_tools** when the project needs only a small subset.\n- Keep prompt approval for state-changing tools and inspect organization\n identifiers on every call.\n- Decide who owns revocation, incident response and correction of an unintended\n change.\n- Remove or disable the server when the project no longer needs application\n access.\n- Treat tool output as untrusted context and use application audit evidence—not\n the conversation alone—to investigate a protected action.";
342
+ readonly sourceRefs: readonly ["saas-technical-doc:engine-content/connect-codex", "source:companion-projection:application-connection"];
343
+ readonly markdown: "# Connect Codex\n\nUse this guide when Codex needs authorized information or operations from this\napplication while helping with a coding task. The connection uses the\napplication's remote MCP server. Codex receives only the tools available to the\nauthenticated identity; adding the server does not create a new role or bypass\norganization access.\n\nYou will register one server, authenticate, inspect the active tool catalogue,\napprove one read-only call and compare the result with the application.\n\n## Choose the configuration scope\n\nCodex CLI, the IDE extension and the ChatGPT desktop app share MCP configuration\non the same Codex host.\n\n| The server is for… | Configuration file | Use it when |\n| --- | --- | --- |\n| Your Codex environment | **~/.codex/config.toml** | You need the application across your own trusted workspaces |\n| One trusted project | **.codex/config.toml** in that project | The team has approved sharing the server declaration with the project |\n\nA project file may contain the server URL and approval policy. It must not\ncontain a personal bearer token or another person's credential.\n\n## Register the remote server\n\nAdd this table to the selected configuration file:\n\n~~~toml\n[mcp_servers.application]\nurl = \"{{APPLICATION_CONNECTION_VALUE:mcpEndpointUrl}}\"\ndefault_tools_approval_mode = \"prompt\"\n~~~\n\nThe URL above is this application’s MCP endpoint. Confirm it belongs to the environment\nyou intend before connecting. Keep **/api/v1/mcp** exactly once. The prompt approval mode means\nCodex asks before using tools from this server.\n\nThe [official Codex MCP documentation](https://learn.chatgpt.com/docs/extend/mcp?surface=cli)\ndefines the current configuration keys, Streamable HTTP support, OAuth login\nand per-server tool controls.\n\n## Confirm registration and authenticate\n\nIn a terminal on the same host, run **codex mcp list**. The output should include\n**application** with the URL you configured. If it is missing, correct the file\nand scope before attempting authentication.\n\nStart the interactive OAuth flow:\n\n~~~bash\ncodex mcp login application\n~~~\n\nComplete sign-in for the intended non-production environment and organization.\nThen open Codex and use **/mcp**. Confirm that the **application** server is\nactive and inspect its tools.\n\n> **Keep credentials out of configuration and prompts.** Interactive users\n> should use the OAuth login. If an administrator deliberately provides a\n> machine token, store it in a protected environment variable and configure\n> only its variable name with **bearer_token_env_var**.\n\n## Inspect the tool before calling it\n\nStart by asking Codex to reason without executing:\n\n> From the **application** MCP server, identify the tool that can read the known\n> test record. Show the proposed tool name and arguments. **Do not call it.**\n\nCompare the proposed tool with the current **/mcp** catalogue. An empty or\nnarrower catalogue can be correct because the server filters tools for the\nsigned-in identity. Do not guess a missing tool name or paste another person's\ncatalogue into the prompt.\n\n## Prove one read-only call\n\nAsk Codex to call the selected read-only tool for one known organization and\nrecord. At the approval prompt:\n\n1. confirm the server is **application**;\n2. confirm the tool is marked or described as read-only;\n3. inspect organization and resource identifiers;\n4. refuse arguments that are broader than the task; and\n5. approve the call once.\n\nCompare the returned identity and material fields with current application\nstate. The conversation may summarize the result, but the application remains\nthe authoritative source.\n\n~~~mermaid\nflowchart TD\n accTitle: Verify a Codex MCP connection before allowing changes\n accDescr: The user registers the remote server, completes audience-specific authentication, inspects the active tools, approves one read-only call, and compares its result with the application before considering write access.\n config[\"Register remote MCP URL\"] --> auth[\"Complete MCP authentication\"]\n auth --> inspect[\"Inspect /mcp tool catalogue\"]\n inspect --> approve[\"Approve one read-only call\"]\n approve --> compare[\"Compare with application state\"]\n compare --> decision{\"Broader access justified?\"}\n decision -->|No| keep[\"Keep prompt approvals and narrow tools\"]\n decision -->|Yes| govern[\"Document write approvals and recovery\"]\n~~~\n\nThe decision at the end of the diagram is deliberately separate from\nconnectivity. A working read does not justify automatic write approval.\n\n## When Codex does not show the expected result\n\n| What you observe | Check first | Safe next action |\n| --- | --- | --- |\n| **application** absent from **codex mcp list** | Config file, TOML syntax and selected scope | Correct the one intended configuration; do not duplicate the server in user and project scope |\n| Server fails to initialize | URL, network, TLS and **/api/v1/mcp** | Repair reachability before changing roles or credentials |\n| OAuth login does not complete | Environment URL, browser sign-in and callback completion | Retry login for this server; never paste a token into the conversation |\n| Server active, no tools | Active organization, membership, roles and MCP publication | Ask the administrator to verify the intended access boundary |\n| Tool absent | The current **/mcp** catalogue | Use an admitted alternative or request only the required operation/role |\n| Tool returns **403** | Tool arguments and operation authority | Treat the response as an authorization decision; prompt wording cannot grant a role |\n| Write timed out | Application record and audit evidence | Read current state before approving any repeat |\n\n## Before enabling broader use\n\n- Keep the server pinned to one environment; never silently change a shared\n project from test to production.\n- Use **enabled_tools** when the project needs only a small subset.\n- Keep prompt approval for state-changing tools and inspect organization\n identifiers on every call.\n- Decide who owns revocation, incident response and correction of an unintended\n change.\n- Remove or disable the server when the project no longer needs application\n access.\n- Treat tool output as untrusted context and use application audit evidence—not\n the conversation alone—to investigate a protected action.";
344
344
  }, {
345
345
  readonly managedPath: "integrations/ai-tools/claude-code.md";
346
346
  readonly unitRef: "technical-documentation:unit/connect-claude-code";
347
- readonly sourceRefs: readonly ["saas-technical-doc:engine-content/connect-claude-code"];
348
- readonly markdown: "# Connect Claude Code\n\nUse this guide when Claude Code should read or act on information in this\napplication through the current person's authorization. The connection uses a\nremote MCP server. Claude Code can see only the tools admitted for that identity,\norganization and role; installing the server does not grant access by itself.\n\nYou will add one server, authenticate, inspect the caller-specific tool list,\napprove one read-only call and compare its result with application state.\n\n## Choose where the connection belongs\n\nClaude Code supports local, project and user scopes. Choose the narrowest scope\nthat matches the work:\n\n| Scope | Use it when | Important consequence |\n| --- | --- | --- |\n| Local | Only your current project checkout needs the server | The declaration remains personal to this local setup |\n| Project | Everyone who trusts the project should be offered the server | The shared project configuration must contain no personal token or secret |\n| User | You need the server across your own projects | The server becomes available broadly in your Claude Code environment |\n\nStart with local scope unless a reviewed team or personal-wide need exists.\n\n## Add the remote HTTP server\n\nRun this from the intended project:\n\n~~~bash\nclaude mcp add --transport http application <server-origin>/api/v1/mcp\n~~~\n\nReplace **<server-origin>** with the server origin for the intended application\nenvironment and keep **/api/v1/mcp** exactly once. Add **--scope project** or\n**--scope user** only after making the scope decision above.\n\nThe [current Claude Code MCP documentation](https://code.claude.com/docs/en/mcp)\nowns the command syntax, remote HTTP transport, scopes, OAuth and server status\ncontrols.\n\n## Confirm the server and authenticate\n\nRun **claude mcp list**. Confirm that **application** appears with the exact\nnon-production URL you selected. If it is absent or reports a configuration\nproblem, repair that before signing in.\n\nStart Claude Code and open its MCP controls. Complete authentication when\nrequested, using your own application identity and the intended organization.\nThe authorization must be for the application MCP server. A general REST API\nkey or token for another audience is not an interchangeable substitute.\n\n## Inspect the available tools first\n\nAsk Claude Code to plan without executing:\n\n> From the **application** MCP server, identify the tool that can read the known\n> test record. Show the tool name and proposed arguments. **Do not call it.**\n\nCompare the proposal with the current server tool list. A colleague may see more\ntools because their organization or roles differ. Never paste their catalogue\ninto your instructions or guess a missing tool name.\n\n## Test one bounded read\n\nAsk Claude Code to use the selected read-only tool for a record whose result you\ncan recognize. Before approving the call:\n\n1. confirm that the tool belongs to the **application** server;\n2. inspect the organization and resource identifiers;\n3. confirm that the described operation is read-only;\n4. refuse the call if any argument is broader than the task; and\n5. approve one execution.\n\nCompare the returned record identity and material fields with the application.\nDo not rely on the conversational summary alone.\n\n~~~mermaid\nsequenceDiagram\n accTitle: Use Claude Code with a caller-specific application tool catalogue\n accDescr: Claude Code connects to the remote HTTP server, the person completes authentication, the server returns only authorized tools, and the person approves one bounded call before trusting the connection.\n participant Person\n participant Claude as Claude Code\n participant App as Application MCP server\n Person->>Claude: Add environment-specific server\n Claude->>App: Discover and initialize\n Person->>App: Authenticate for MCP audience\n Claude->>App: tools/list\n App-->>Claude: Authorized catalogue\n Person->>Claude: Approve one bounded tool call\n Claude->>App: tools/call\n App-->>Claude: Result or access refusal\n~~~\n\nThe tool catalogue in the sequence belongs to the signed-in caller. A successful\nconnection with no expected tool is usually an access or publication question,\nnot a reason to weaken approval controls.\n\n## Troubleshoot without widening access\n\n| What you observe | Check first | Safe next action |\n| --- | --- | --- |\n| Server missing | Selected scope and **claude mcp list** | Add or repair one declaration in the intended scope; do not add duplicates to every scope |\n| Configuration error | URL, transport and command syntax | Correct the remote HTTP declaration using the official reference |\n| Authentication repeats | Environment URL and completion of this server's sign-in | Re-authenticate for the intended environment; never paste a token into a prompt |\n| Connected, but no tools | Active organization, membership, roles and published MCP operations | Ask the application administrator to verify the intended boundary |\n| Expected tool absent | Current caller-specific catalogue | Use an admitted alternative or request only the needed role/operation |\n| Tool refused | Tool arguments and structured access response | Treat it as an authorization result; do not grant a broader role unless the business task requires it |\n| Write outcome unclear | Current application record and audit evidence | Read authoritative state before approving another call |\n\n## Before approving a state-changing tool\n\n- Keep tool approval enabled and inspect every organization and resource\n identifier.\n- Agree on the intended change and the read that will verify it.\n- Decide how a timeout or interrupted response will be reconciled before another\n call is allowed.\n- Keep secrets out of project configuration, prompts and transcripts.\n- Treat tool descriptions, results and links as untrusted context that can\n influence the model.\n- Use the application's audit trail—not the conversation alone—to investigate a\n protected action.\n- Remove the server or its authorization when the project no longer needs\n access.";
347
+ readonly sourceRefs: readonly ["saas-technical-doc:engine-content/connect-claude-code", "source:companion-projection:application-connection"];
348
+ readonly markdown: "# Connect Claude Code\n\nUse this guide when Claude Code should read or act on information in this\napplication through the current person's authorization. The connection uses a\nremote MCP server. Claude Code can see only the tools admitted for that identity,\norganization and role; installing the server does not grant access by itself.\n\nYou will add one server, authenticate, inspect the caller-specific tool list,\napprove one read-only call and compare its result with application state.\n\n## Choose where the connection belongs\n\nClaude Code supports local, project and user scopes. Choose the narrowest scope\nthat matches the work:\n\n| Scope | Use it when | Important consequence |\n| --- | --- | --- |\n| Local | Only your current project checkout needs the server | The declaration remains personal to this local setup |\n| Project | Everyone who trusts the project should be offered the server | The shared project configuration must contain no personal token or secret |\n| User | You need the server across your own projects | The server becomes available broadly in your Claude Code environment |\n\nStart with local scope unless a reviewed team or personal-wide need exists.\n\n## Add the remote HTTP server\n\nRun this from the intended project:\n\n~~~bash\nclaude mcp add --transport http application {{APPLICATION_CONNECTION_VALUE:mcpEndpointUrl}}\n~~~\n\nThe URL above is this application’s MCP endpoint. Confirm it belongs to the environment\nyou intend before connecting, and keep **/api/v1/mcp** exactly once. Add **--scope project** or\n**--scope user** only after making the scope decision above.\n\nThe [current Claude Code MCP documentation](https://code.claude.com/docs/en/mcp)\nowns the command syntax, remote HTTP transport, scopes, OAuth and server status\ncontrols.\n\n## Confirm the server and authenticate\n\nRun **claude mcp list**. Confirm that **application** appears with the exact\nnon-production URL you selected. If it is absent or reports a configuration\nproblem, repair that before signing in.\n\nStart Claude Code and open its MCP controls. Complete authentication when\nrequested, using your own application identity and the intended organization.\nThe authorization must be for the application MCP server. A general REST API\nkey or token for another audience is not an interchangeable substitute.\n\n## Inspect the available tools first\n\nAsk Claude Code to plan without executing:\n\n> From the **application** MCP server, identify the tool that can read the known\n> test record. Show the tool name and proposed arguments. **Do not call it.**\n\nCompare the proposal with the current server tool list. A colleague may see more\ntools because their organization or roles differ. Never paste their catalogue\ninto your instructions or guess a missing tool name.\n\n## Test one bounded read\n\nAsk Claude Code to use the selected read-only tool for a record whose result you\ncan recognize. Before approving the call:\n\n1. confirm that the tool belongs to the **application** server;\n2. inspect the organization and resource identifiers;\n3. confirm that the described operation is read-only;\n4. refuse the call if any argument is broader than the task; and\n5. approve one execution.\n\nCompare the returned record identity and material fields with the application.\nDo not rely on the conversational summary alone.\n\n~~~mermaid\nsequenceDiagram\n accTitle: Use Claude Code with a caller-specific application tool catalogue\n accDescr: Claude Code connects to the remote HTTP server, the person completes authentication, the server returns only authorized tools, and the person approves one bounded call before trusting the connection.\n participant Person\n participant Claude as Claude Code\n participant App as Application MCP server\n Person->>Claude: Add environment-specific server\n Claude->>App: Discover and initialize\n Person->>App: Authenticate for MCP audience\n Claude->>App: tools/list\n App-->>Claude: Authorized catalogue\n Person->>Claude: Approve one bounded tool call\n Claude->>App: tools/call\n App-->>Claude: Result or access refusal\n~~~\n\nThe tool catalogue in the sequence belongs to the signed-in caller. A successful\nconnection with no expected tool is usually an access or publication question,\nnot a reason to weaken approval controls.\n\n## Troubleshoot without widening access\n\n| What you observe | Check first | Safe next action |\n| --- | --- | --- |\n| Server missing | Selected scope and **claude mcp list** | Add or repair one declaration in the intended scope; do not add duplicates to every scope |\n| Configuration error | URL, transport and command syntax | Correct the remote HTTP declaration using the official reference |\n| Authentication repeats | Environment URL and completion of this server's sign-in | Re-authenticate for the intended environment; never paste a token into a prompt |\n| Connected, but no tools | Active organization, membership, roles and published MCP operations | Ask the application administrator to verify the intended boundary |\n| Expected tool absent | Current caller-specific catalogue | Use an admitted alternative or request only the needed role/operation |\n| Tool refused | Tool arguments and structured access response | Treat it as an authorization result; do not grant a broader role unless the business task requires it |\n| Write outcome unclear | Current application record and audit evidence | Read authoritative state before approving another call |\n\n## Before approving a state-changing tool\n\n- Keep tool approval enabled and inspect every organization and resource\n identifier.\n- Agree on the intended change and the read that will verify it.\n- Decide how a timeout or interrupted response will be reconciled before another\n call is allowed.\n- Keep secrets out of project configuration, prompts and transcripts.\n- Treat tool descriptions, results and links as untrusted context that can\n influence the model.\n- Use the application's audit trail—not the conversation alone—to investigate a\n protected action.\n- Remove the server or its authorization when the project no longer needs\n access.";
349
349
  }, {
350
350
  readonly managedPath: "integrations/agents.md";
351
351
  readonly unitRef: "technical-documentation:unit/agent-interoperability";
@@ -354,67 +354,72 @@ export declare const APPLICATION_CONSUMER_DOCUMENTATION_AUTHORED_CONTENT_V1: rea
354
354
  }, {
355
355
  readonly managedPath: "integrations/create-your-own-integration.md";
356
356
  readonly unitRef: "technical-documentation:unit/first-request";
357
- readonly sourceRefs: readonly ["saas-technical-doc:engine-content/first-request", "source:consumer-fact:access-api-keys"];
358
- readonly markdown: "# Create your own integration\n\nUse this guide when **your service must call this application's REST API** and\nnone of the ready-made automation guides fits the job. You will make one\nauthenticated read in a non-production organization, prove that the security\nboundary works, and then decide whether the integration is ready to make one\ncontrolled change.\n\n> **Looking for a different kind of connection?** If the application should\n> notify your system, start with [Webhooks](/integrations/webhooks). If n8n,\n> Zapier or Make will run the workflow, use\n> [Automation platforms](/integrations/automation-platforms). MCP and A2A have\n> separate [Agent integration](/integrations/agents) guides.\n\n## What will you have at the end?\n\nA successful first integration is deliberately small. It can:\n\n- authenticate with a credential created for **one workload**;\n- read one known piece of information from **one intended organization**;\n- show a response that matches the current API reference;\n- demonstrate that the same operation is refused without valid access; and\n- explain what to do if a later write times out before a response is received.\n\nThis is enough to prove the connection. Scheduling, high volume, automatic\nretries and a larger data mapping come later.\n\n~~~mermaid\nsequenceDiagram\n accTitle: Prove a custom integration before it changes application data\n accDescr: An integration owner selects an authenticated read from the API reference, creates a dedicated credential, proves the allowed request and an expected refusal, and only then adds one controlled write with a read-back recovery path.\n actor Owner as Integration owner\n participant Reference as API reference\n participant Service as Your service\n participant App as Application API\n Owner->>Reference: Choose one authenticated read\n Owner->>Service: Store server, path and dedicated credential\n Service->>App: Send the documented request\n App-->>Service: Return the documented success response\n Service->>App: Repeat without valid access\n App-->>Service: Refuse the request\n Owner->>Service: Permit one controlled write\n Service->>App: Write, then read back authoritative state\n~~~\n\nThe important sequence is **read, refusal, then write**. A successful read\nalone proves connectivity; the refusal proves that your test did not bypass the\naccess boundary.\n\n## Before you open your code editor\n\nCollect these values. Do not guess any of them from another environment or\nanother application.\n\n| What you need | Where to find it | What to record |\n| --- | --- | --- |\n| Server origin | The server selector at the top of the API reference | The complete scheme and host, without adding another API prefix |\n| Read operation | One **GET** operation in the API reference that permits the intended credential | Method, operation path, required parameters and documented success status |\n| Organization | The non-production organization approved for the test | Its identifier and where the selected operation expects it |\n| Credential | [Create and store an API key](/access-and-identity/api-keys-create-and-store) | A dedicated key with the smallest role accepted by the operation |\n| Expected record | The application itself | One record or collection whose visible result you can recognize |\n\n> **Do not use a personal administrator credential for a deployed service.** A\n> service needs its own credential so that its access can be reviewed, rotated\n> or revoked without affecting a person.\n\n## Step 1: choose a harmless read\n\nOpen the **API reference** from the top navigation and choose the normal\napplication API. Start with a GET operation that reads a collection or a known\nrecord; do not start with an administrative or state-changing operation.\n\nOn the operation page, confirm all of the following:\n\n1. the operation supports the credential type you intend to use;\n2. the documented role requirement matches the key you were given;\n3. you know where the organization and resource identifiers belong;\n4. you have copied the request path exactly; and\n5. you know which success response and body shape to expect.\n\nIf any of those items is unclear, stop here. A broader key does not repair an\nunclear operation contract.\n\n## Step 2: send the request once\n\nReplace the two angle-bracket placeholders with the server origin and operation\npath from the same API-reference environment. The generated authorization line\nis the application's maintained API-key transport contract.\n\n~~~bash\ncurl --fail-with-body --url \"<server-origin><documented-operation-path>\" {{CONSUMER_FACT:source:consumer-fact:access-api-keys#curlRequestHeader}} --header \"accept: application/json\"\n~~~\n\nAdd only the parameters required by the selected operation. If the reference\nplaces the organization in the path, query or body, keep it there—do not invent\nan additional organization header.\n\n### What should you see?\n\nThe request is a valid connection proof only when:\n\n- the HTTP status is one of the operation's documented success responses;\n- the JSON shape matches that response, including its collection wrapper when\n one is documented;\n- the returned information belongs to the intended organization; and\n- the known record or collection result is recognizable in the application.\n\nRecord the operation identity, environment, organization, time, status and a\nnon-secret correlation identifier if the response supplies one. **Never copy\nthe API key into a log, ticket, screenshot or test fixture.**\n\n## Step 3: prove the request is protected\n\nRepeat the same authenticated operation in the same non-production environment\nwithout sending a valid credential. The operation should return the documented\nauthentication refusal, normally **401**. Restore the credential immediately\nafter the test.\n\nThen test the narrowest relevant authorization boundary: for example, a key\nwithout the required role or an organization the workload should not access.\nConfirm the documented refusal or absence behavior. Do not add authority merely\nto turn a refusal into a success; first establish whether the refusal is the\ncorrect result.\n\n## Step 4: add one business change\n\nOnly add a write when the business outcome requires one. Choose one documented\ncreate or update operation and use a target that a person can inspect safely.\n\nBefore sending it, write down:\n\n- the current state;\n- the exact state that should change;\n- the state that must remain unchanged; and\n- the read operation that will prove the final result.\n\nSend the write once, then read the target back from the application. A client\nsuccess message is useful, but the read-back is the authoritative verification.\n\n> **A timeout is not a safe retry signal.** It means your service did not\n> receive the response; the application may still have completed the change.\n> Read the target's current state before deciding whether another write is\n> necessary.\n\n## If the first request fails\n\n| What you observe | Check first | Safe next action |\n| --- | --- | --- |\n| No HTTP response | Server origin, DNS, TLS and network reachability | Correct the connection; do not rotate a credential that was never presented |\n| 400-series validation response | Required path/query values and the request schema | Compare the submitted values field by field with the operation reference |\n| **401** | Selected environment, authorization transport and key lifecycle | Restore the correct active key; never print the key while diagnosing |\n| **403** | Required role, organization membership and operation authority | Request only the missing approved authority; do not switch to an administrator key |\n| **404** | Resource identifier, organization scope and visibility rules | Confirm the target in the application before changing the request |\n| Conflict response | Current resource state or concurrency requirement | Read current state and reconcile; do not blindly repeat the write |\n| Timeout or server failure after a write | Authoritative application state | Read back the target before any retry |\n\nContinue with [Troubleshoot an API request](/integrations/rest/troubleshoot)\nwhen the response still does not identify the failing boundary.\n\n## Before the integration runs unattended\n\n- Move the credential into the deployment platform's secret store.\n- Give the workload, credential and alert an accountable human owner.\n- Validate response shapes and reject unexpected enum values before acting on\n them.\n- Bound concurrency and retries; use backoff for failures that are safe to\n repeat.\n- Reconcile timeouts, conflicts and duplicate work from authoritative state.\n- Prove how to revoke the credential and stop the workload during an incident.\n- Retain identifiers, statuses and correlation evidence—not secrets or\n unrestricted response bodies.\n\nNext, read [REST API](/integrations/rest-api) for the complete request journey,\nincluding collections, controlled writes and troubleshooting.";
357
+ readonly sourceRefs: readonly ["saas-technical-doc:engine-content/first-request", "source:companion-projection:application-connection", "source:consumer-fact:access-api-keys"];
358
+ readonly markdown: "# Create your own integration\n\nUse this guide when **your service must call this application's REST API** and\nnone of the ready-made automation guides fits the job. You will make one\nauthenticated read in a non-production organization, prove that the security\nboundary works, and then decide whether the integration is ready to make one\ncontrolled change.\n\n> **Looking for a different kind of connection?** If the application should\n> notify your system, start with [Webhooks](/integrations/webhooks). If n8n,\n> Zapier or Make will run the workflow, use\n> [Automation platforms](/integrations/automation-platforms). MCP and A2A have\n> separate [Agent integration](/integrations/agents) guides.\n\n## What will you have at the end?\n\nA successful first integration is deliberately small. It can:\n\n- authenticate with a credential created for **one workload**;\n- read one known piece of information from **one intended organization**;\n- show a response that matches the current API reference;\n- demonstrate that the same operation is refused without valid access; and\n- explain what to do if a later write times out before a response is received.\n\nThis is enough to prove the connection. Scheduling, high volume, automatic\nretries and a larger data mapping come later.\n\n~~~mermaid\nsequenceDiagram\n accTitle: Prove a custom integration before it changes application data\n accDescr: An integration owner selects an authenticated read from the API reference, creates a dedicated credential, proves the allowed request and an expected refusal, and only then adds one controlled write with a read-back recovery path.\n actor Owner as Integration owner\n participant Reference as API reference\n participant Service as Your service\n participant App as Application API\n Owner->>Reference: Choose one authenticated read\n Owner->>Service: Store server, path and dedicated credential\n Service->>App: Send the documented request\n App-->>Service: Return the documented success response\n Service->>App: Repeat without valid access\n App-->>Service: Refuse the request\n Owner->>Service: Permit one controlled write\n Service->>App: Write, then read back authoritative state\n~~~\n\nThe important sequence is **read, refusal, then write**. A successful read\nalone proves connectivity; the refusal proves that your test did not bypass the\naccess boundary.\n\n## Before you open your code editor\n\nCollect these values. Do not guess any of them from another environment or\nanother application.\n\n| What you need | Where to find it | What to record |\n| --- | --- | --- |\n| Server origin | The server selector at the top of the API reference | The complete scheme and host, without adding another API prefix |\n| Read operation | One **GET** operation in the API reference that permits the intended credential | Method, operation path, required parameters and documented success status |\n| Organization | The non-production organization approved for the test | Its identifier and where the selected operation expects it |\n| Credential | [Create and store an API key](/access-and-identity/api-keys-create-and-store) | A dedicated key with the smallest role accepted by the operation |\n| Expected record | The application itself | One record or collection whose visible result you can recognize |\n\n> **Do not use a personal administrator credential for a deployed service.** A\n> service needs its own credential so that its access can be reviewed, rotated\n> or revoked without affecting a person.\n\n## Step 1: choose a harmless read\n\nOpen the **API reference** from the top navigation and choose the normal\napplication API. Start with a GET operation that reads a collection or a known\nrecord; do not start with an administrative or state-changing operation.\n\nOn the operation page, confirm all of the following:\n\n1. the operation supports the credential type you intend to use;\n2. the documented role requirement matches the key you were given;\n3. you know where the organization and resource identifiers belong;\n4. you have copied the request path exactly; and\n5. you know which success response and body shape to expect.\n\nIf any of those items is unclear, stop here. A broader key does not repair an\nunclear operation contract.\n\n## Step 2: send the request once\n\nReplace the two angle-bracket placeholders with the server origin and operation\npath from the same API-reference environment. The generated authorization line\nis the application's maintained API-key transport contract.\n\n~~~bash\ncurl --fail-with-body --url \"{{APPLICATION_CONNECTION_VALUE:baseUrl}}<documented-operation-path>\" {{CONSUMER_FACT:source:consumer-fact:access-api-keys#curlRequestHeader}} --header \"accept: application/json\"\n~~~\n\nAdd only the parameters required by the selected operation. If the reference\nplaces the organization in the path, query or body, keep it there—do not invent\nan additional organization header.\n\n### What should you see?\n\nThe request is a valid connection proof only when:\n\n- the HTTP status is one of the operation's documented success responses;\n- the JSON shape matches that response, including its collection wrapper when\n one is documented;\n- the returned information belongs to the intended organization; and\n- the known record or collection result is recognizable in the application.\n\nRecord the operation identity, environment, organization, time, status and a\nnon-secret correlation identifier if the response supplies one. **Never copy\nthe API key into a log, ticket, screenshot or test fixture.**\n\n## Step 3: prove the request is protected\n\nRepeat the same authenticated operation in the same non-production environment\nwithout sending a valid credential. The operation should return the documented\nauthentication refusal, normally **401**. Restore the credential immediately\nafter the test.\n\nThen test the narrowest relevant authorization boundary: for example, a key\nwithout the required role or an organization the workload should not access.\nConfirm the documented refusal or absence behavior. Do not add authority merely\nto turn a refusal into a success; first establish whether the refusal is the\ncorrect result.\n\n## Step 4: add one business change\n\nOnly add a write when the business outcome requires one. Choose one documented\ncreate or update operation and use a target that a person can inspect safely.\n\nBefore sending it, write down:\n\n- the current state;\n- the exact state that should change;\n- the state that must remain unchanged; and\n- the read operation that will prove the final result.\n\nSend the write once, then read the target back from the application. A client\nsuccess message is useful, but the read-back is the authoritative verification.\n\n> **A timeout is not a safe retry signal.** It means your service did not\n> receive the response; the application may still have completed the change.\n> Read the target's current state before deciding whether another write is\n> necessary.\n\n## If the first request fails\n\n| What you observe | Check first | Safe next action |\n| --- | --- | --- |\n| No HTTP response | Server origin, DNS, TLS and network reachability | Correct the connection; do not rotate a credential that was never presented |\n| 400-series validation response | Required path/query values and the request schema | Compare the submitted values field by field with the operation reference |\n| **401** | Selected environment, authorization transport and key lifecycle | Restore the correct active key; never print the key while diagnosing |\n| **403** | Required role, organization membership and operation authority | Request only the missing approved authority; do not switch to an administrator key |\n| **404** | Resource identifier, organization scope and visibility rules | Confirm the target in the application before changing the request |\n| Conflict response | Current resource state or concurrency requirement | Read current state and reconcile; do not blindly repeat the write |\n| Timeout or server failure after a write | Authoritative application state | Read back the target before any retry |\n\nContinue with [Troubleshoot an API request](/integrations/rest/troubleshoot)\nwhen the response still does not identify the failing boundary.\n\n## Before the integration runs unattended\n\n- Move the credential into the deployment platform's secret store.\n- Give the workload, credential and alert an accountable human owner.\n- Validate response shapes and reject unexpected enum values before acting on\n them.\n- Bound concurrency and retries; use backoff for failures that are safe to\n repeat.\n- Reconcile timeouts, conflicts and duplicate work from authoritative state.\n- Prove how to revoke the credential and stop the workload during an incident.\n- Retain identifiers, statuses and correlation evidence—not secrets or\n unrestricted response bodies.\n\nNext, read [REST API](/integrations/rest-api) for the complete request journey,\nincluding collections, controlled writes and troubleshooting.";
359
359
  }, {
360
360
  readonly managedPath: "integrations/rest-api.md";
361
361
  readonly unitRef: "technical-documentation:unit/common-rest-api";
362
362
  readonly sourceRefs: readonly ["saas-technical-doc:engine-content/common-rest-api"];
363
- readonly markdown: "# REST API\n\nUse the REST API when another system needs to read or change application data\nand needs an immediate response. This section explains the decisions shared by\nREST integrations. The generated API reference remains authoritative for exact\npaths, fields, roles, statuses and resource-specific limits.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Name one business outcome, the system that owns it, the organization in scope and the identity that should perform it | A repeatable request reaches the intended environment, proves only the required access and can be reconciled safely after failure |\n\n## Decide whether REST matches the work\n\n| Need | Use | Why |\n| --- | --- | --- |\n| Read current application state now | REST read operation | The caller receives an immediate representation of what it is allowed to see |\n| Ask the application to make a change now | REST write operation | The caller receives an immediate success, refusal or ambiguous transport outcome |\n| React when the application publishes an event | **Webhooks** (published under Integrations when the application exposes an outbound delivery surface) | The application initiates delivery after the event; polling is not required |\n| Let an AI tool discover and invoke approved tools | **MCP** (published under Integrations when the application exposes an MCP tool surface) | Tool discovery and invocation are different from a fixed REST integration |\n\nREST describes the request/response transport. It does not decide who should\nown a business workflow, which organization is implied or whether a write is\nsafe to repeat. Those decisions belong to the integration design and the exact\noperation contract.\n\n## Follow the request lifecycle\n\n~~~mermaid\nflowchart LR\n accTitle: Build and reconcile a REST API request\n accDescr: The integration selects an environment and operation, authenticates a dedicated identity, validates the response, then either commits the result or reconciles an ambiguous outcome.\n choose[\"Select environment and documented operation\"] --> auth[\"Authenticate the intended identity\"]\n auth --> send[\"Send a schema-valid request\"]\n send --> result{\"Unambiguous result?\"}\n result -->|Yes| commit[\"Record outcome and correlation\"]\n result -->|No| read[\"Read authoritative state\"]\n read --> reconcile[\"Reconcile before any retry\"]\n~~~\n\nThe most important branch is the last one. A timeout means that **the client did\nnot receive a result**; it does not prove that the server made no change.\n\n## Keep four boundaries visible\n\n1. **Environment:** the server origin identifies where the request goes. Never\n infer production from a path copied from another deployment.\n2. **Identity:** the operation states which credential types it accepts. Use a\n dedicated workload credential for unattended work.\n3. **Organization and visibility:** a valid identity can still be unable to see\n a resource outside its organization or authorized unit scope.\n4. **Operation contract:** request fields, enum values, roles, response shape\n and failure meanings are specific to the chosen operation.\n\nAn HTTP success is transport evidence, not the final business proof. Verify the\nreturned identity and scope for reads, and re-read authoritative state after a\nwrite when the business result matters.\n\n## Choose the next task\n\n- [Send your first API request](/integrations/rest/send-request) to establish\n environment, authentication and scope.\n- [Read collections reliably](/integrations/rest/read-collections) to handle\n pagination, filtering and visibility without losing or duplicating work.\n- [Write and reconcile changes](/integrations/rest/write-and-reconcile) before\n adding automatic retries to mutations.\n- [Troubleshoot an API request](/integrations/rest/troubleshoot) using the\n response class and correlation evidence.\n\n## Keep the guide and reference in their roles\n\nThis guide explains **why and in what order** to act. The API reference tells\nyou **what this application publishes**. Never copy an operation from another\napplication or infer a writable field from a response example. Start with\n[one safe request](/integrations/rest/send-request), not with retries, bulk\nprocessing or a production mutation.";
363
+ readonly markdown: "# REST API\n\nThe REST API lets another system read and change this application's data with an immediate answer. Everything the application shows in its own screens is reachable the same way: each screen is backed by the operations listed in the [API reference](/api), and an integration calls those operations directly.\n\n## What you get\n\n- One JSON API under `/api/v1`, documented operation by operation in the API reference: path, method, request fields, response shape, accepted credentials, required roles and the failures each operation can return.\n- One set of conventions shared by every operation: how to authenticate, how collections page and sort, what an error looks like, how limits and optimistic locking work. They are on one page, [REST API conventions](/integrations/rest/conventions), so the reference does not have to repeat them.\n- Two credential kinds. An **API key** is a long-lived secret for software that acts on behalf of an organization or the whole application. A **bearer token** is what a signed-in person or an OAuth client holds. [API keys](/access-and-identity/api-keys) explains how to create one and what it may do.\n\n## Choose the right tool first\n\n| You need to | Use | Why |\n| --- | --- | --- |\n| Read or change data now, and know the result | REST | The application answers each request with the outcome |\n| React after something happens in the application | [Webhooks](/integrations/webhooks) | The application calls you; no polling |\n| Let an AI assistant work with the application | [MCP](/integrations/mcp) | Tools are discovered and invoked by the assistant, not scripted by you |\n| Build in n8n, Zapier or Make | [Automation platforms](/integrations/automation-platforms) | Those tools already speak REST; the guides show the exact settings |\n\n## The four pages of this section\n\n1. [Send your first API request](/integrations/rest/send-request): reach the right environment with the right credential and prove it in ten minutes.\n2. [Read collections](/integrations/rest/read-collections): page, sort, search and filter without skipping or duplicating records.\n3. [Write and reconcile changes](/integrations/rest/write-and-reconcile): make a change once, use optimistic locking, and recover from a lost response.\n4. [Troubleshoot an API request](/integrations/rest/troubleshoot): turn a status code and an error body into the one thing to fix.\n\nKeep [REST API conventions](/integrations/rest/conventions) open beside the API reference while you work; it is the page these guides point at for exact names and values.";
364
+ }, {
365
+ readonly managedPath: "integrations/rest/conventions.md";
366
+ readonly unitRef: "technical-documentation:unit/rest-api-conventions";
367
+ readonly sourceRefs: readonly ["saas-technical-doc:engine-content/rest-api-conventions", "source:companion-projection:application-connection", "source:consumer-fact:access-api-keys", "source:consumer-fact:rest-conventions"];
368
+ readonly markdown: "# REST API conventions\n\nEvery operation in the API reference follows the same rules for addressing, authentication, collections, writes, errors and limits. Read this page once. After that, an operation's entry in the reference only has to tell you what is specific to it: its path, its fields, the roles it accepts and the failures it can return.\n\n## Addressing\n\n- Every path in the API reference already starts with the `/api/v1` mount. Prepend the base URL of the environment you are calling:\n\n{{APPLICATION_CONNECTION:baseUrls}}\n\n- Organization data lives under `/api/v1/organizations/{organizationId}/…`. The organization identifier is the one shown in the application. A collection under an organization your credential is not a member of answers **403**; a single record that belongs to another organization answers **404**, so that the application never confirms what exists outside your scope.\n- The same resource is often reachable through more than one parent path (for example through the organization directly and through a related record). Those paths are aliases of one operation and answer with the same data; use whichever matches the identifiers you already hold.\n- Send and expect `application/json`. Identifiers are opaque strings: store them, compare them, never parse them.\n- Header names are case-insensitive; this documentation writes them the way the application emits them.\n\n## Authentication\n\n{{CONSUMER_FACT:source:consumer-fact:access-api-keys#markdown}}\n\nSigned-in people and OAuth clients use a bearer token instead: `Authorization: Bearer <access token>`. Each operation's **Security** entry in the reference lists which of the two it accepts. Send exactly one credential per request.\n\n## Collections\n\nList and search operations share one query vocabulary:\n\n{{CONSUMER_FACT:source:consumer-fact:rest-conventions#collectionQueryMarkdown}}\n\n{{CONSUMER_FACT:source:consumer-fact:rest-conventions#paginationResponseMarkdown}}\n\nA concrete request and its response, using the members of your own organization:\n\n~~~bash\ncurl --fail-with-body \\\n --url \"$BASE_URL/api/v1/organizations/$ORGANIZATION_ID/organization-members?page=1&limit=20&sort=joinedAt:desc\" \\\n --header \"Authorization: $ORGANIZATION_API_KEY\" \\\n --header \"accept: application/json\"\n~~~\n\n~~~json\n{\n \"data\": [\n {\n \"_id\": \"0d3f2a9e-6c41-4b7a-8e15-5f9c2b7d4a10\",\n \"userId\": \"b8e4c2f1-3a57-4d09-9f6e-1c2d3e4f5a6b\",\n \"userEmail\": \"alex.morgan@example.com\",\n \"organizationId\": \"7c1f6f0a-4b1e-4d8f-9a0c-2e5b3c9d1f42\",\n \"roles\": [\"ORG_MEMBER\"],\n \"status\": \"ACTIVE\",\n \"createdAt\": \"2026-07-03T09:15:00.000Z\",\n \"updatedAt\": \"2026-08-18T08:00:00.000Z\",\n \"_version\": 4\n }\n ],\n \"pagination\": { \"page\": 1, \"limit\": 20, \"total\": 1, \"totalPages\": 1 }\n}\n~~~\n\n## Writes\n\n- The reference states each operation's success status and the fields it accepts. A field you see in a read response is not automatically writable; send only what the request schema lists.\n- Operations marked **idempotent** in the reference can be repeated safely. For any other write, a lost response is an ambiguous outcome: read the record back before sending the write again. [Write and reconcile changes](/integrations/rest/write-and-reconcile) shows the procedure.\n- Bulk variants (`…/bulk` paths) apply one change to several identifiers. Read the operation's response schema before assuming every identifier was applied, and reconcile each one with a read after a failure.\n\n{{CONSUMER_FACT:source:consumer-fact:rest-conventions#concurrencyMarkdown}}\n\n## Errors\n\n{{CONSUMER_FACT:source:consumer-fact:rest-conventions#errorEnvelopeMarkdown}}\n\nFor example, removing the last owner of an organization is refused like this:\n\n~~~json\n{{CONSUMER_FACT:source:consumer-fact:rest-conventions#errorExampleJson}}\n~~~\n\nBranch on the HTTP status first, then on `error.type`, and on `error.code` only for refusals the operation documents by name:\n\n{{CONSUMER_FACT:source:consumer-fact:rest-conventions#errorStatusMarkdown}}\n\n## Rate limits\n\nThe application enforces several windows at once and reports the tightest one:\n\n{{CONSUMER_FACT:source:consumer-fact:rest-conventions#rateLimitMarkdown}}\n\nBack off when `x-ratelimit-remaining` reaches zero rather than waiting for the **429**. Parallel workers share the same counters when they share a credential.\n\n## Support evidence\n\nWhen you ask for help, quote the operation path, the HTTP status, `error.type`, `error.code` when present, and `error.correlationId`. That identifier joins your request to the application's logs and audit trail and contains no personal data. Never paste a credential, a bearer token or a full response body into a ticket.";
364
369
  }, {
365
370
  readonly managedPath: "integrations/rest/send-request.md";
366
371
  readonly unitRef: "technical-documentation:unit/send-api-request";
367
- readonly sourceRefs: readonly ["saas-technical-doc:engine-content/send-api-request", "source:consumer-fact:access-api-keys"];
368
- readonly markdown: "# Send your first API request\n\nYour first request should prove four things and nothing more: you reached the\ncorrect environment, the credential is accepted, the identity can see the\nintended organization and the response matches the published schema. Choose a\nread operation that has no business side effect.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Have the environment's server origin, one documented read operation, a dedicated credential accepted by that operation and one expected visible resource | The request returns the documented result in the intended scope, an expected refusal remains refused, and the credential can be revoked independently |\n\n~~~mermaid\nflowchart TD\n accTitle: Prove an API connection from environment to business scope\n accDescr: The integration owner selects a harmless documented read, targets one environment, sends an accepted credential, validates the response schema and organization scope, then confirms an expected refusal before allowing any write.\n operation[\"Choose one harmless documented read\"] --> environment[\"Set the exact environment origin\"]\n environment --> credential[\"Send one accepted dedicated credential\"]\n credential --> response{\"Documented success response?\"}\n response -->|No| diagnose[\"Diagnose transport, authentication, authority or visibility\"]\n response -->|Yes| schema[\"Validate schema and intended organization\"]\n schema --> refusal[\"Confirm one expected refusal\"]\n refusal --> ready[\"Record proof and prepare one controlled write\"]\n~~~\n\n## What you need\n\n- the server origin from this application's API reference;\n- one documented read operation;\n- a dedicated API key or another credential explicitly accepted by that operation;\n- an organization and resource that the identity is expected to see.\n\nChoose a request that is easy for a human to recognize afterwards. A list or\nsingle-resource read in a test organization is usually better than a broad\nexport. Record the expected identifier or count before calling the API so that\nyou can distinguish “valid JSON” from the correct business result.\n\nCopy the operation path and parameters from the API reference. For an API key,\nsend the key in the standard authorization header:\n\n~~~bash\ncurl --fail-with-body --url \"<server-origin>/<documented-path>\" {{CONSUMER_FACT:source:consumer-fact:access-api-keys#curlRequestHeader}} --header \"accept: application/json\"\n~~~\n\nReplace only the placeholders shown by the exact API reference. Do not add a\n`Bearer` prefix to an API key, put credentials in the URL, or print the fully\nexpanded command into an ordinary build log. For a user or delegated OAuth\njourney, use the credential scheme documented by that operation instead of\nsending two credentials and relying on accidental precedence.\n\n## Verify the result\n\nDo not stop at “the request returned JSON.” Confirm:\n\n1. the status is the documented success status;\n2. the response conforms to the operation schema;\n3. the returned organization and resource are the ones you intended;\n4. the credential can be identified and revoked without affecting another workload;\n5. logs contain correlation and outcome data but not the credential.\n\nThen run one **negative proof**: request an operation this identity is\ndeliberately not allowed to use, without probing another customer's known\nidentifier. The documented refusal demonstrates that scope enforcement remains\npresent; it is as important as the successful read.\n\nIf the request fails, use the status class before changing anything: 401 points\nto authentication, 403 to authority, and 404 to identity, scope or resource\nselection. Do not create a more privileged credential until you know which\ndecision failed.\n\n## Before the first write\n\nRepeat the read from the deployment environment, then revoke or rotate the test\ncredential to prove the operating procedure. Only then choose one small write\nand define how you will detect whether it applied after a timeout.\n\nRecord the environment, operation identity, credential's non-secret identifier,\norganization, expected business result, observed status and correlation value.\nThat is enough to reproduce the connection proof without retaining the secret\nor an unrestricted response payload.";
372
+ readonly sourceRefs: readonly ["saas-technical-doc:engine-content/send-api-request", "source:companion-projection:application-connection", "source:consumer-fact:access-api-keys"];
373
+ readonly markdown: "# Send your first API request\n\nTen minutes from an API key to a verified connection. The first request proves four things and nothing else: you reached the right environment, the credential is accepted, it sees the organization you expect, and you can read the response. Use a read operation that changes nothing.\n\n## What you need\n\n- The **base URL** of the environment you are calling. {{APPLICATION_NAME}} publishes these:\n\n{{APPLICATION_CONNECTION:baseUrls}}\n\n- Your **organization identifier**, shown in the application's organization settings and present in the URL of most screens.\n- An **organization API key** created for this integration, following [Create and store an API key](/access-and-identity/api-keys-create-and-store). Keep it in a secret store or an environment variable, never in the request URL or a build log.\n\nGive the request a name in your notes before you send it. \"List the members of the Support organization, expect Alex Morgan\" is a result you can check; \"the call returned JSON\" is not.\n\n## Step 1: read your own organization\n\nThe safest first call reads the organization the key belongs to. It needs no other identifier and changes nothing.\n\n~~~bash\nBASE_URL=\"https://api.example.com\" # from the API reference's Servers list\nORGANIZATION_ID=\"7c1f6f0a-4b1e-4d8f-9a0c-2e5b3c9d1f42\" # from the application's organization settings\nORGANIZATION_API_KEY=\"sk_org_…\" # the key you created\n\ncurl --fail-with-body \\\n --url \"$BASE_URL/api/v1/organizations/$ORGANIZATION_ID\" \\\n {{CONSUMER_FACT:source:consumer-fact:access-api-keys#curlRequestHeader}} \\\n --header \"accept: application/json\"\n~~~\n\nReplace the three values with yours; leave the header exactly as shown. {{CONSUMER_FACT:source:consumer-fact:access-api-keys#markdown}}\n\nA successful answer is **200** with the organization record: its `_id` is the identifier you sent, and `name` is the organization you expected. Anything else, read the [failure table](#if-it-fails) below before changing more than one thing.\n\n## Step 2: read a collection\n\nNow list the organization's members. This exercises the collection envelope you will meet on every list and search operation:\n\n~~~bash\ncurl --fail-with-body \\\n --url \"$BASE_URL/api/v1/organizations/$ORGANIZATION_ID/organization-members?limit=5&sort=joinedAt:desc\" \\\n --header \"Authorization: $ORGANIZATION_API_KEY\" \\\n --header \"accept: application/json\"\n~~~\n\nThe response is `{ \"data\": [ … ], \"pagination\": { \"page\": 1, \"limit\": 5, \"total\": …, \"totalPages\": … } }`. Check that `total` matches the member count you see in the application. [Read collections](/integrations/rest/read-collections) covers paging, sorting and filters in full.\n\n## Step 3: prove the boundary holds\n\nA connection is only safe when a wrong credential is refused. Send the first request again with the key deliberately broken:\n\n~~~bash\ncurl --include \\\n --url \"$BASE_URL/api/v1/organizations/$ORGANIZATION_ID\" \\\n --header \"Authorization: sk_org_not_a_real_key\" \\\n --header \"accept: application/json\"\n~~~\n\nExpect **401** with `\"type\": \"AUTHENTICATION\"` in the error body. Then send the correct key against an organization it does not belong to and expect **404**: the application does not confirm that organizations outside your scope exist. Those two refusals are the negative proof; record them beside the successful read.\n\n## If it fails\n\n| You see | It means | Do this |\n| --- | --- | --- |\n| No response, or a TLS or DNS error | The base URL is wrong or unreachable from where you run | Compare the URL with the Servers list; test from the network the integration will run on |\n| **401** `AUTHENTICATION` | The key was not accepted | Check the header carries the full key with no `Bearer` prefix, that the key is `active`, and that it belongs to this environment |\n| **403** `AUTHORIZATION` | The key is valid but its roles do not allow this operation | Compare the roles on the key with the roles the operation lists in the reference |\n| **404** `NOT_FOUND` | The organization identifier is wrong, or this key cannot see it | Copy the identifier from the application again |\n| **429** `RATE_LIMIT` | Too many requests | Wait `Retry-After` seconds |\n\nEvery error an operation produces carries `error.correlationId`. Quote it when you ask for help. [Troubleshoot an API request](/integrations/rest/troubleshoot) goes deeper.\n\n## Before your first write\n\nRepeat Step 1 from the environment where the integration will actually run. Then rotate the key once ([API key lifecycle](/access-and-identity/api-keys-lifecycle)) to prove that the operating procedure works before you depend on it. Only then choose one small write and read [Write and reconcile changes](/integrations/rest/write-and-reconcile).";
369
374
  }, {
370
375
  readonly managedPath: "integrations/rest/read-collections.md";
371
376
  readonly unitRef: "technical-documentation:unit/work-with-api-collections";
372
- readonly sourceRefs: readonly ["saas-technical-doc:engine-content/work-with-api-collections"];
373
- readonly markdown: "# Read collections reliably\n\nA collection is the set of records one operation lets the caller see **in its\ncurrent organization and access scope**. It is not automatically every record\nin the application. A reliable integration reads that visible set in bounded\npages, processes each record safely and can resume without silently skipping or\nduplicating business work.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Choose one documented list or search operation, the organization in scope, the filters that express the business question and a stable way to recognize processed records | Every returned page is validated and checkpointed, completion follows the returned pagination metadata, and a repeated or resumed scan does not create a duplicate business effect |\n\n## Begin with the business question\n\nWrite down what the scan is meant to answer before choosing parameters. “Read\nall records” is usually too broad. Prefer a bounded outcome such as:\n\n- reconcile records changed during a defined operating window;\n- find records in a documented state that need attention;\n- copy the minimum fields required for a downstream report;\n- verify that a previous write produced the intended current state.\n\nThen open the exact operation in the API reference. Confirm the response item,\navailable filters and sort fields, pagination ceiling and required authority.\n**A parameter accepted by one collection is not a platform-wide convention.**\nDo not reuse a filter name, page size or sort order from another resource.\n\n## Read one page at a time\n\nWhen the API reference declares page and limit parameters, the response carries\nthe current page, limit, total count and total pages with the returned data.\nProcess the current page successfully before advancing. Stop from returned\npagination metadata; do not guess from a short page or copy a maximum size from\nanother resource.\n\n~~~mermaid\nflowchart TD\n accTitle: Consume a paginated collection without skipping work\n accDescr: The integration requests one documented page, validates and processes it, records progress, and advances only while returned pagination metadata says another page exists.\n request[\"Request documented page\"] --> validate[\"Validate response and scope\"]\n validate --> process[\"Process page idempotently\"]\n process --> checkpoint[\"Persist progress\"]\n checkpoint --> more{\"Returned metadata shows another page?\"}\n more -->|Yes| request\n more -->|No| done[\"Collection pass complete\"]\n~~~\n\nFollow that lifecycle in order:\n\n1. Request the first documented page with an explicit, supported limit and only\n the filters needed for the business question.\n2. Validate the response envelope and each item before using its fields. Check\n that the result belongs to the intended environment and organization.\n3. Process each record **idempotently**. Reprocessing the same stable record\n identifier must not create a second payment, message, account or other\n business effect.\n4. Persist a checkpoint only after the page's work is safely recorded. Keep the\n page number, filter and sort basis, stable identifiers or counts, and the\n returned pagination metadata.\n5. Advance only while the response says another page exists. Do not stop merely\n because a page contains fewer items than requested.\n\nAn empty first page can be a correct result. Prove it by confirming the caller,\norganization, filters and expected visibility rather than treating emptiness as\na transport failure.\n\n## Read the pagination metadata literally\n\nThe standard collection envelope contains the returned data plus **page**,\n**limit**, **total** and **totalPages**. These values describe the server's\nanswer to that request:\n\n- **page** identifies the page just returned;\n- **limit** is the page size applied by that operation;\n- **total** is the matching record count reported for the query;\n- **totalPages** tells the caller whether another numbered page remains.\n\nDo not manufacture a next page from the number of items alone. If the operation\npublishes a different paging model, follow that operation instead of translating\nit into this one.\n\n## Decide how changes during a scan are handled\n\nRecords may be created or changed while a multi-page scan runs. If the exact\noperation does not publish snapshot or cursor semantics, do not claim a\npoint-in-time view. Make downstream processing idempotent, retain stable record\nidentifiers and schedule a reconciliation pass appropriate to the business risk.\n\nChoose the recovery posture before production:\n\n- For a low-risk report, a later complete pass may be sufficient.\n- For a state synchronization, persist stable identifiers and compare the final\n downstream state with a fresh authoritative read.\n- For financial, access or other sensitive effects, use a documented stable\n ordering or change marker when available and explicitly investigate gaps.\n- If the scan fails halfway through, resume from the last **completed**\n checkpoint. Reprocessing the boundary page is safer than skipping uncertain\n work when processing is idempotent.\n\nNever assume that page 2 still starts after the same record if concurrent\nchanges can reorder the collection. The operation contract determines whether a\nstable scan is possible; the client cannot create that guarantee by remembering\nonly a page number.\n\n## Verify completion\n\nCompare the processed count and checkpoints with the final returned metadata,\nthen sample a small number of recognizable records in the intended organization.\nRun one controlled repeat and confirm it produces no duplicate downstream\neffect. If records can change during the pass, run the planned reconciliation\nand explain any difference rather than forcing the counts to appear equal.\n\nRetain the operation identity, environment, organization, filter and sort basis,\nstart/end time, pages processed, final pagination metadata and non-sensitive\ncheckpoint. Do not log full result sets merely to prove the scan ran; store the\nminimum identifiers and counts needed to investigate omissions or duplicates.\n\n## Continue safely\n\n- [Write and reconcile changes](/integrations/rest/write-and-reconcile) before\n turning collection results into mutations.\n- [Troubleshoot an API request](/integrations/rest/troubleshoot) when one page\n fails or visibility differs from the expected organization scope.\n- Return to [REST API](/integrations/rest-api) to review the request, identity,\n organization and operation boundaries.";
377
+ readonly sourceRefs: readonly ["saas-technical-doc:engine-content/work-with-api-collections", "source:consumer-fact:rest-conventions"];
378
+ readonly markdown: "# Read collections\n\nA collection is the set of records one list or search operation lets your credential see in one organization. Read it in pages, sort it deliberately, filter it on the fields the operation offers, and stop where the response says to stop. Every list and search operation in the API reference uses the vocabulary below.\n\n## The query vocabulary\n\n{{CONSUMER_FACT:source:consumer-fact:rest-conventions#collectionQueryMarkdown}}\n\nFilter and sort fields are per operation. Each operation's entry in the API reference lists them as query parameters, so open the operation before writing the request; a filter accepted by one resource is not a convention for another.\n\n## The response envelope\n\n{{CONSUMER_FACT:source:consumer-fact:rest-conventions#paginationResponseMarkdown}}\n\nAn empty `data` array on page 1 is a valid answer. Confirm the organization and the filters before treating it as a failure.\n\n## Walk every page\n\n~~~bash\npage=1\nwhile : ; do\n response=$(curl --fail-with-body --silent \\\n --url \"$BASE_URL/api/v1/organizations/$ORGANIZATION_ID/organization-members?page=$page&limit=100&sort=joinedAt:asc\" \\\n --header \"Authorization: $ORGANIZATION_API_KEY\" \\\n --header \"accept: application/json\")\n echo \"$response\" | jq -c '.data[]' >> members.ndjson\n totalPages=$(echo \"$response\" | jq '.pagination.totalPages')\n [ \"$page\" -ge \"$totalPages\" ] && break\n page=$((page + 1))\ndone\n~~~\n\nThree rules keep a scan correct:\n\n1. **Sort by a field the reference lists as sortable, or a stable timestamp** such as `joinedAt:asc` for members, when you walk more than one page. A sort field the operation does not accept is ignored, not refused, and the default order applies; sorting by a field that changes during the scan (a status, a name being edited) can move a record between pages and make you skip or repeat it.\n2. **Stop on `totalPages`**, not on a short page. The last page is short by definition; an earlier page is short only when records were deleted while you scanned.\n3. **Process each record idempotently** and key your own records on `_id`. If the scan is interrupted, resume from the last page whose work you completed; repeating a page is safe when processing is idempotent, skipping one never is.\n\n## Search and filter\n\nSearch operations (`…/search`) add `q` for free text. Combine it with filters and sorting:\n\n~~~bash\ncurl --fail-with-body \\\n --url \"$BASE_URL/api/v1/organizations/$ORGANIZATION_ID/organization-members/search?q=morgan&status=ACTIVE&sort=joinedAt:desc\" \\\n --header \"Authorization: $ORGANIZATION_API_KEY\" \\\n --header \"accept: application/json\"\n~~~\n\nDate-range filters are objects and use bracket notation, one key per bound:\n\n~~~text\n?createdAt[startDate]=2026-09-01T00:00:00Z&createdAt[endDate]=2026-09-30T23:59:59Z\n~~~\n\nSend instants in ISO 8601 with a timezone. An unparseable bound answers **400** with the field named in `error.validationErrors`.\n\n## Counts and summaries\n\nBeside the full list, most collections expose `…/summary`, which answers the fields the application uses for pickers and tables and is smaller and faster than the full record. Some also expose `…/count`, which answers only the total without loading records. The API reference shows which variants an operation has. Use them for dashboards and reconciliation counts; use the full list only when you need every field.\n\n## Reconcile a long scan\n\nRecords can change while a scan runs. When the scan feeds a report, a later complete pass corrects it. When it feeds a synchronization, keep the `_id` and `_version` of each record you processed and compare them with a fresh read before you overwrite anything downstream; `_version` increases on every write, so a changed value tells you the record moved.\n\n## When a page fails\n\nA failed page answers with the same error envelope as any request; the status table in [REST API conventions](/integrations/rest/conventions#errors) says what each status means. A **429** carries `Retry-After`; wait that long before resuming from the same page. Do not resume from page 1.";
374
379
  }, {
375
380
  readonly managedPath: "integrations/rest/write-and-reconcile.md";
376
381
  readonly unitRef: "technical-documentation:unit/write-and-reconcile-api-changes";
377
- readonly sourceRefs: readonly ["saas-technical-doc:engine-content/write-and-reconcile-api-changes"];
378
- readonly markdown: "# Write and reconcile API changes\n\nA write is complete only when the integration knows the authoritative outcome.\nAn HTTP method does not by itself make a mutation safe to repeat, and a client\ntimeout does not prove that nothing changed.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Choose one documented write, a test organization, a least-privilege identity, the expected current state and a stable way to recognize the intended business change | One controlled change reaches the expected state, an unauthorized or invalid change remains refused, and a lost response can be reconciled without creating a duplicate effect |\n\n## Define the business identity of the change\n\nBefore sending the request, decide which stable application or external\nidentifier lets you recognize the same intended change later. Use a documented\nidempotency contract when the operation publishes one. Otherwise, prevent\nconcurrent duplicate work in your own system and reconcile from authoritative\nstate after uncertainty.\n\nSeparate three identifiers where the business process has them:\n\n- the **request attempt**, which can happen more than once;\n- the **intended business change**, which should happen once;\n- the **resulting application record**, which proves the current state.\n\nDo not invent an idempotency header or client token unless the exact operation\ndocuments one. A locally generated identifier is still useful for your logs and\nwork queue, but it does not make the server deduplicate the request.\n\n## Prepare one controlled write\n\n1. Read the target resource and record the fields that form the expected\n pre-change state.\n2. Validate the request locally against the published schema. Send only fields\n the write accepts; a field returned by a read is not automatically writable.\n3. Confirm the caller, organization and role immediately before the mutation.\n Use a dedicated workload identity rather than a person's broad credential.\n4. Send the change once and retain the status, stable error code and correlation\n identifier without retaining the credential or unrestricted payload.\n5. Read the authoritative resource again. Verify the intended state and scope,\n not only the HTTP success response.\n6. Exercise one expected refusal—for example insufficient authority or an\n invalid transition—and confirm that authoritative state did not change.\n\n~~~mermaid\nstateDiagram-v2\n accTitle: Reconcile a state-changing API request\n accDescr: A prepared change is sent once. A confirmed response records success or refusal. A timeout or lost response enters an ambiguous state that must be resolved by reading authoritative application state before retrying.\n [*] --> Prepared\n Prepared --> Sent\n Sent --> Confirmed: documented success\n Sent --> Refused: unambiguous failure\n Sent --> Ambiguous: timeout or connection loss\n Ambiguous --> Confirmed: authoritative state shows applied\n Ambiguous --> SafeToRetry: authoritative state shows not applied\n SafeToRetry --> Sent\n Confirmed --> [*]\n Refused --> [*]\n~~~\n\nThe **Ambiguous** state is operationally important. It means the client cannot\nyet classify the business outcome. It is not success, failure or permission to\nsend the mutation again.\n\n## Reconcile an ambiguous outcome\n\nWhen the connection closes, times out or loses the response:\n\n1. Stop automatic retries for that business change.\n2. Read the target through the documented authoritative operation.\n3. Compare its current state with both the pre-change state and intended result.\n4. If the result is present, record the original attempt as applied even though\n its response was lost.\n5. If the result is absent and the read is conclusive, allow one bounded retry\n under the same business-change identity.\n6. If the state is conflicting or visibility is insufficient, route the item\n for human reconciliation instead of guessing.\n\nFor create operations, reconcile using a documented stable business key or a\nsearch that can identify the new record. If no reliable lookup exists, the\noperation is not yet safe for unattended retries.\n\n## Treat failures by meaning\n\n- **Validation failure:** correct the request; do not retry unchanged.\n- **401 or 403:** repair identity or authority; more retries cannot grant access.\n- **404:** check identifier and visible organization scope before assuming absence.\n- **409:** read current state and resolve the business conflict.\n- **429 or retryable server failure:** follow the documented delay and use\n bounded backoff.\n- **Timeout or connection loss:** read authoritative state before deciding\n whether another write is safe.\n\nA successful write can still be the wrong business result—for example, it may\ntarget the wrong organization or apply a broader role than intended. Always\ncompare the resulting resource with the approved change, not merely with the\nresponse schema.\n\n## Protect concurrent work\n\nIf people or other integrations can change the same record, read-modify-write\nlogic needs a conflict strategy. Use the operation's documented version,\nprecondition or conflict semantics when available. Otherwise minimize the\nfields written, re-read before overwriting, and route conflicting state for\nreview. A blind retry after **409** can erase another actor's valid change.\n\n## Preserve useful evidence\n\nRetain the intended change identity, operation, target scope, attempt number,\nstatus, stable error code and correlation identifier. Redact credentials,\npersonal data and restricted request or response fields. Also retain the\nnon-sensitive before/after proof needed to show whether the business change was\napplied, refused or reconciled.\n\nThe production workflow is ready only when operators can answer: **What did we\nintend, what did the application finally contain, and why was another attempt\nsafe or refused?**\n\n## Continue safely\n\n- [Read collections reliably](/integrations/rest/read-collections) when writes\n are driven from a collection or need a later reconciliation pass.\n- [Troubleshoot an API request](/integrations/rest/troubleshoot) to classify a\n refusal, conflict or transport failure without destroying evidence.\n- Return to [REST API](/integrations/rest-api) to review the shared authority and\n scope boundaries.";
382
+ readonly sourceRefs: readonly ["saas-technical-doc:engine-content/write-and-reconcile-api-changes", "source:consumer-fact:rest-conventions"];
383
+ readonly markdown: "# Write and reconcile changes\n\nA write is finished when you know what the application now contains, not when the HTTP call returns. This page shows how to make a change once, how to refuse to overwrite someone else's change, and what to do when the response never arrives.\n\n## Send the change\n\n1. Open the operation in the API reference and copy its request schema. Send only the fields it lists; a field you saw in a read is not necessarily writable.\n2. Read the record first and keep its `_version`.\n3. Send the write with the version in the `if-match` header.\n4. Read the record again and compare the fields you changed with what you intended. A **200** proves the application accepted the request; the second read proves the business result.\n\nUpdating a member's roles, with optimistic locking:\n\n~~~bash\ncurl --fail-with-body \\\n --request PUT \\\n --url \"$BASE_URL/api/v1/organizations/$ORGANIZATION_ID/organization-members/$MEMBER_ID\" \\\n --header \"Authorization: $ORGANIZATION_API_KEY\" \\\n --header \"content-type: application/json\" \\\n --header \"if-match: 4\" \\\n --data '{ \"roles\": [\"ORG_MANAGER\"] }'\n~~~\n\n{{CONSUMER_FACT:source:consumer-fact:rest-conventions#concurrencyMarkdown}}\n\nWithout `if-match` the write applies unconditionally, last writer wins. Use the header whenever a person or another integration can touch the same record.\n\n## Read the refusal\n\nA write the application will not perform answers with the standard error envelope. Three cases matter for a writer:\n\n| Status | `error.type` | What happened | What to do |\n| --- | --- | --- | --- |\n| **400** | `VALIDATION` | The body breaks the schema; `error.validationErrors` names each field | Fix the request. Resending it unchanged fails again |\n| **409** | `CONFLICT` | A stale `if-match`, a uniqueness rule, or a state transition the record forbids | Read the record, then decide: merge and resend, or stop because the change no longer applies |\n| **422** | `BUSINESS_RULE` | The request is well-formed but a domain rule refuses it; `error.customMessageReference` names the rule | Only a different request, or a different state, can succeed |\n\nFor example, removing the last owner of an organization answers **409** with `error.code` set to `LAST_ORGANIZATION_OWNER`: grant owner access to another member first, then retry. The [REST API conventions](/integrations/rest/conventions#errors) page lists every status and error type.\n\n## Recover from a lost response\n\nA timeout, a dropped connection or a crash between sending and reading the answer leaves the outcome unknown. Do not resend on reflex; the application may already have applied the change.\n\n1. Stop automatic retries for this change.\n2. Read the target record. For a create, search for it by the business key you sent (an email, a reference number, a name).\n3. If the change is there, treat the original attempt as applied and continue.\n4. If it is absent, send it once more. Include the same `if-match` value you used the first time when the record existed before; a **409** now means something else changed in between.\n5. If the state is neither what you expected before nor after, hand the item to a person with the request you sent, the record you read and both timestamps.\n\nOperations marked **idempotent** in the API reference can be resent without this procedure. Everything else needs it.\n\n## Bulk changes\n\nBulk variants (`…/bulk` paths) take a list of identifiers and apply one change to each. Read the operation's response schema in the API reference before assuming that every identifier was applied, and after a failure reconcile each identifier individually with a read. Do not resend the whole batch because one item failed.\n\n## Keep the right evidence\n\nFor each change keep the operation path, the identifiers, the `if-match` value, the status, `error.type` and `error.code` when refused, and `error.correlationId`. That is enough to answer \"what did we intend, what does the application contain, and why was a second attempt safe or refused\". Never store the credential or the full request body next to it.";
379
384
  }, {
380
385
  readonly managedPath: "integrations/rest/troubleshoot.md";
381
386
  readonly unitRef: "technical-documentation:unit/troubleshoot-api-request";
382
- readonly sourceRefs: readonly ["saas-technical-doc:engine-content/troubleshoot-api-request"];
383
- readonly markdown: "# Troubleshoot an API request\n\nBegin with what the application actually returned. Replacing credentials,\nchanging organizations and retrying at the same time destroys the evidence that\nwould distinguish an authentication problem from an authorization or data\nproblem.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Preserve one failed attempt's time, environment, operation, caller reference, organization, status and correlation evidence | The failure is assigned to one boundary, the smallest safe correction is tested, and any uncertain write is reconciled before another attempt |\n\n## Keep the original failure intact\n\nFirst copy the non-secret evidence from the failed attempt. Do not rotate the\ncredential, alter the request and change the target environment simultaneously.\nConfirm whether the request received an HTTP response at all, then classify the\nfirst failing boundary.\n\n~~~mermaid\nflowchart TD\n accTitle: Diagnose an API request without hiding the original failure\n accDescr: The operator preserves evidence, separates transport from HTTP response, then checks request contract, authentication, authority, visibility, conflict or server failure before applying one bounded correction and re-proving the business result.\n failure[\"Preserve one failed attempt\"] --> response{\"HTTP response received?\"}\n response -->|No| transport[\"Check environment, DNS, TLS and timeout\"]\n response -->|Yes| class{\"Which response class?\"}\n class -->|400| contract[\"Validate exact operation contract\"]\n class -->|401| identity[\"Validate credential and environment\"]\n class -->|403 or 404| scope[\"Validate authority, organization and visibility\"]\n class -->|409| conflict[\"Read and reconcile current state\"]\n class -->|429 or 5xx| retry[\"Follow documented delay and safety rule\"]\n transport --> prove[\"Apply one correction and repeat the proof\"]\n contract --> prove\n identity --> prove\n scope --> prove\n conflict --> prove\n retry --> prove\n~~~\n\n## Diagnose one boundary at a time\n\n| Symptom | Most likely boundary | First checks |\n| --- | --- | --- |\n| No HTTP response | Network, DNS, TLS or server availability | Target environment, resolved host, TLS result and timeout |\n| **400** or validation error | Request does not match the operation contract | Content type, required fields, enum values and parameter placement |\n| **401** | Credential was not accepted | Header transport, expiry, revocation, credential type and environment |\n| **403** | Identity lacks authority for the operation | Active organization, membership, role and operation requirements |\n| **404** | Resource is absent or invisible in this scope | Identifier, organization and resource visibility |\n| **409** | Current state conflicts with the requested transition | Read authoritative state and resolve the business conflict |\n| **429** | Caller exceeded an enforced limit | Stop immediate retries and follow the documented delay |\n| **5xx** | Server could not complete the request | Preserve correlation evidence; retry only when the operation is safe |\n\n## Check the boundaries in order\n\n### 1. Environment and transport\n\nConfirm the server origin belongs to the intended deployment. Preserve the DNS,\nTLS and timeout result. A connection refusal, certificate failure and client\ntimeout are different observations even though none returns an application\nstatus. Do not switch to a different environment merely to obtain a response.\n\n### 2. Request contract\n\nCompare the method, content type, parameters, body and enum values with the\nexact operation in the API reference. Validate the request before sending it\nagain. Do not remove unknown fields one at a time in production; build a minimal\nschema-valid reproduction in a safe organization.\n\n### 3. Credential and identity\n\nFor **401**, confirm the header scheme, credential type, expiry or revocation\nstate, and that the credential belongs to this environment. Do not test by\nsubstituting an administrator's credential: that hides the workload identity\ndefect and expands the blast radius.\n\n### 4. Authority and visibility\n\nFor **403**, the identity is known but cannot perform this operation in this\nscope. Confirm active organization membership, role and operation authority.\nFor **404**, confirm the identifier and organization visibility before deciding\nthe record does not exist; an inaccessible record can intentionally be\nindistinguishable from a missing one.\n\n### 5. Current state and retry safety\n\nFor **409**, read the resource and resolve the conflicting state. For **429**,\nhonour the documented delay and stop parallel callers from immediately filling\nthe same limit again. For **5xx** or transport loss, determine whether the\noperation is safe to repeat. A read can usually be repeated; a write first needs\nauthoritative reconciliation.\n\n## Build a safe investigation record\n\nCapture the time, environment, operation identity, caller identity reference,\norganization, status, stable error code and correlation identifier. Replace\npayload values with a minimal redacted reproduction. Never paste an API key,\nBearer token or unrestricted personal data into a ticket.\n\nFor a write with no response, investigate the authoritative resource before\nrepeating it. The absence of a client response is an **ambiguous outcome**, not\nan automatic retry instruction.\n\n## Prove the repair\n\nRepeat the smallest safe request with one change only. Confirm the expected\nsuccess and one expected refusal, then verify the business result in the\nintended organization. If the correction involved a credential or permission,\nalso confirm that access outside the approved scope remains refused.\n\nEscalate with the redacted investigation record, the exact operation reference,\nthe correlation identifier and what authoritative state currently shows. State\nwhether a write may already have applied. That gives support enough context to\ninvestigate without asking for credentials or a full personal-data payload.\n\n## Continue safely\n\n- [Send your first API request](/integrations/rest/send-request) to rebuild the\n connection proof from a harmless read.\n- [Write and reconcile changes](/integrations/rest/write-and-reconcile) before\n retrying a mutation with an uncertain outcome.\n- Return to [REST API](/integrations/rest-api) to review the four shared\n integration boundaries.";
387
+ readonly sourceRefs: readonly ["saas-technical-doc:engine-content/troubleshoot-api-request", "source:consumer-fact:access-api-keys", "source:consumer-fact:rest-conventions"];
388
+ readonly markdown: "# Troubleshoot an API request\n\nStart from what the application returned: the HTTP status and the error body. Together they name the one boundary that failed. Change one thing, resend, and keep the first failure's evidence until the fix is proven.\n\n## Read the status and the error body\n\nEvery failed request answers with the same envelope. The two fields to read first are `error.type` and, when present, `error.code`:\n\n{{CONSUMER_FACT:source:consumer-fact:rest-conventions#errorEnvelopeMarkdown}}\n\n{{CONSUMER_FACT:source:consumer-fact:rest-conventions#errorStatusMarkdown}}\n\n## No HTTP response at all\n\nA connection refusal, a DNS failure, a TLS error and a client timeout are different problems, and none of them is an application answer.\n\n- Compare the base URL with the **Servers** list in the API reference; a URL copied from another environment is the usual cause.\n- Test from the network the integration runs on, not only from a laptop.\n- A timeout on a read can be repeated. A timeout on a write is an ambiguous outcome: follow [Recover from a lost response](/integrations/rest/write-and-reconcile#recover-from-a-lost-response) before resending.\n\n## 401: the credential was not accepted\n\n- The `Authorization` header must carry the whole key, with no `Bearer` prefix in front of an API key and no key inside a URL or a cookie. {{CONSUMER_FACT:source:consumer-fact:access-api-keys#markdown}}\n- Check the key's status in the application: an `inactive` or `expired` key is refused. [API key lifecycle](/access-and-identity/api-keys-lifecycle) explains each status.\n- Check the environment: a key minted in one environment does not work in another.\n\nDo not fix a 401 by borrowing an administrator's key. That hides the defect and widens what the integration can do.\n\n## 403: valid credential, refused operation\n\nThe application knows who is calling and refuses this operation in this scope.\n\n- Compare the roles on the key with the roles the operation lists in the API reference.\n- A collection under an organization the key is not a member of is refused with 403; confirm the organization identifier.\n- `FEATURE_NOT_AVAILABLE` and `FEATURE_LIMIT_EXCEEDED` are plan refusals, not role refusals; see [Plans and access](/billing-and-subscriptions/plans-and-access).\n\n## 404: the record is not visible here\n\nEither the identifier is wrong or the record belongs to an organization this key cannot see. The application does not distinguish the two on purpose. Copy the identifier from the application again and confirm the organization in the path.\n\n## 409 and 422: the current state refuses the change\n\nRead the record, then read `error.code` and `error.customMessageReference`. A stale `if-match` carries `error.details.versionConflict` with the current version. [Write and reconcile changes](/integrations/rest/write-and-reconcile) shows what to do for each case.\n\n## 429: too many requests\n\n{{CONSUMER_FACT:source:consumer-fact:rest-conventions#rateLimitMarkdown}}\n\nWait the full `Retry-After`, then resume where you stopped. If several workers share one key they share its counters; spread the load or use one key per worker.\n\n## 5xx: the application failed\n\nKeep `error.correlationId`, the operation path and the time. Reads can be retried with a short back-off. For a write, read the record before resending.\n\n## Prove the fix\n\nResend the smallest request with exactly one change. Then run the two negative checks from [Send your first API request](/integrations/rest/send-request#step-3-prove-the-boundary-holds) again: a wrong key is still refused, and another organization is still invisible. A fix that opened the boundary is not a fix.\n\n## Ask for help with the right evidence\n\nQuote the operation path, the HTTP status, `error.type`, `error.code`, `error.correlationId` and the timestamp. Say whether a write may already have applied. Never paste the key, a bearer token or a full response body.";
384
389
  }, {
385
390
  readonly managedPath: "integrations/webhooks.md";
386
391
  readonly unitRef: "technical-documentation:unit/webhooks";
387
- readonly sourceRefs: readonly ["saas-technical-doc:engine-content/webhooks"];
388
- readonly markdown: "# Webhooks\n\nUse a webhook when another system should react after this application publishes\nan event. The application sends a signed HTTP request to your receiver. Your\nreceiver decides whether the request is authentic, applies the business effect\nonce and returns an HTTP result.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Know which published event starts the work, who owns the receiving system, where its public HTTPS endpoint runs and how duplicate work will be prevented | Authentic deliveries are accepted quickly, each event produces the business effect at most once, and failed or ambiguous work can be reconciled |\n\n## Decide whether an event should drive the work\n\n| Situation | Better starting point | Reason |\n| --- | --- | --- |\n| Another system must react soon after a published event | Webhook | The application initiates a delivery instead of making the receiver poll |\n| Another system needs the current state now | [REST API](/integrations/rest-api) | A request retrieves authoritative state at the moment it is needed |\n| The receiver must recover after missing or delaying an event | Webhook plus REST reconciliation | The event starts the work; an authoritative read confirms the final state |\n| No published event represents the business change | REST or a different supported integration | A webhook endpoint cannot invent application events |\n\nA webhook is a **notification**, not a remote command and not a permanent copy\nof application state. Design the receiver so the event starts bounded work and\nthe application remains the authority for facts that can change afterwards.\n\n## Understand the records involved\n\n- An **endpoint** identifies the receiver, its enabled state and the events it\n is configured to receive.\n- An **event** is the notification payload produced by one application\n operation. One notification can create a separate delivery for each matching\n endpoint.\n- A **delivery** tracks that notification for one endpoint and carries the\n signed identity the receiver uses for deduplication.\n- A **delivery attempt** records one HTTP exchange and its result. Retries are\n additional attempts for the same delivery, not new business events.\n\nThis distinction is why the receiver deduplicates with the signed delivery\nidentity and why operators investigate delivery state separately from the\ndownstream business effect.\n\n~~~mermaid\nsequenceDiagram\n accTitle: Receive and apply a webhook delivery safely\n accDescr: The application signs the raw body and sends it to the receiver. The receiver verifies the token and body hash, atomically deduplicates the delivery identifier, queues the business work, and returns a success response.\n participant App as Application\n participant Receiver as Your receiver\n participant Store as Deduplication store\n participant Worker as Your worker\n App->>Receiver: POST raw body plus signature\n Receiver->>Receiver: Verify ES256 token, claims, expiry and raw-body SHA-256\n Receiver->>Store: Atomically claim signed delivery identifier jti\n Store-->>Receiver: New or already processed\n Receiver->>Worker: Queue new business work\n Receiver-->>App: 2xx after safe acceptance\n~~~\n\nThe receiver must verify before trusting or parsing the event. A success\nresponse means the application observed a 2xx response; it does not independently\nprove what checks your receiver performed.\n\n## Split responsibilities deliberately\n\n| Application sends | Receiver must do |\n| --- | --- |\n| Signed raw payload and delivery identity | Verify the signature and body hash before trusting fields |\n| Delivery attempts with bounded retry behavior | Atomically recognize a previously accepted delivery |\n| HTTP result and limited response evidence | Return quickly after durable acceptance and process longer work asynchronously |\n| Delivery status for operations | Reconcile the downstream business effect after ambiguous processing |\n\nDo not acknowledge before the delivery is durably safe to process. Do not keep\nthe application connection open while performing a long external workflow.\nDurable queueing between those two moments makes fast acknowledgement and safe\nrecovery compatible.\n\n## Follow the journey\n\n- [Configure and test an endpoint](/integrations/webhooks/configure-and-test)\n before enabling production delivery.\n- [Verify a webhook delivery](/integrations/webhooks/verify-delivery) using the\n raw bytes, public key and signed claims.\n- [Operate webhook deliveries](/integrations/webhooks/operate-deliveries) with\n fast acknowledgement, durable work and reconciliation.\n- [Troubleshoot webhook deliveries](/integrations/webhooks/troubleshoot) from\n delivery state and response meaning.\n\nThe event and API references remain authoritative for the exact events,\npayloads and configuration operations exposed by this application. Before\nproduction, prove a valid delivery, an invalid signature, a duplicate delivery,\na receiver timeout and recovery from a failed downstream effect.";
392
+ readonly sourceRefs: readonly ["saas-technical-doc:engine-content/webhooks", "source:companion-projection:application-integration", "source:consumer-fact:outbound-webhooks"];
393
+ readonly markdown: "# Webhooks\n\nA webhook lets the application call your system when something happens, instead of your system polling for it. Each event becomes one signed `POST` to every enabled endpoint you configured. Your receiver verifies the signature, records the delivery once, answers quickly, and does the real work afterwards.\n\n## What the application sends\n\n- **One `POST` per event per endpoint.** The body is the same JSON the operation that fired the event returns to an API caller, so the record you receive has the shape documented for that operation in the [API reference](/api).\n- **A signature in every request.** {{CONSUMER_FACT:source:consumer-fact:outbound-webhooks#signatureMarkdown}}\n- **Retries on your behalf.** {{CONSUMER_FACT:source:consumer-fact:outbound-webhooks#retryMarkdown}}\n\n## The events this application publishes\n\n{{APPLICATION_INTEGRATION:webhookEvents}}\n\n## What you configure\n\n{{CONSUMER_FACT:source:consumer-fact:outbound-webhooks#endpointMarkdown}}\n\nWhich operations fire an event is decided by the application, per resource and operation; the `resourceIdentifier` and `operationIdentifier` claims on each delivery tell you which one did. There is one configuration per organization, managed by organization administrators, and one for the application as a whole, managed by application administrators.\n\n## What your receiver must do\n\n| Step | Why it cannot be skipped |\n| --- | --- |\n| Keep the raw request bytes | The signature covers the exact bytes; a JSON parser that reformats them breaks the check |\n| Verify the token and the body hash before reading the body | Anything before verification is an unauthenticated write into your system |\n| Claim `jti` atomically before doing work | Retries carry the same `jti`; two concurrent attempts must produce one effect |\n| Answer within the timeout, then do the work | A slow receiver is retried, then marked failed, while the work may have half-run |\n| Reconcile against the application for anything money- or access-related | A `delivered` row proves a 2xx, not that your worker finished |\n\n## The four pages of this section\n\n1. [Configure and test an endpoint](/integrations/webhooks/configure-and-test): register a receiver, run the built-in test, enable it.\n2. [Verify a webhook delivery](/integrations/webhooks/verify-delivery): the signature, the claims and a working receiver in Node.js.\n3. [Operate webhook deliveries](/integrations/webhooks/operate-deliveries): delivery statuses, the retry ladder, monitoring and manual retry.\n4. [Troubleshoot webhook deliveries](/integrations/webhooks/troubleshoot): from a failed or missing delivery to the boundary that broke.";
389
394
  }, {
390
395
  readonly managedPath: "integrations/webhooks/configure-and-test.md";
391
396
  readonly unitRef: "technical-documentation:unit/configure-and-test-webhook-endpoint";
392
- readonly sourceRefs: readonly ["saas-technical-doc:engine-content/configure-and-test-webhook-endpoint"];
393
- readonly markdown: "# Configure and test a webhook endpoint\n\nCreate a receiver that is publicly reachable, preserves the raw request body\nand can return quickly. Use HTTPS for production. The endpoint URL must not\ncontain embedded credentials, and the application does not follow redirects.\n\nThis task is for the administrator who controls the application endpoint and\nthe engineer who controls the receiving service. Complete it together: a green\nHTTP result proves reachability, while the receiver's own evidence proves that\nit verified the signed request before acknowledging it.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Choose one organization or application scope, one final HTTPS receiver URL, one published event and an owner for receiver incidents; prepare signature verification, deduplication and durable queueing | A disabled endpoint accepts a signed synthetic test, rejects an invalid request, then processes one controlled real event exactly once after staged enablement |\n\n## Choose the endpoint boundary\n\nCreate a separate endpoint for each receiver lifecycle that needs independent\nenablement, ownership or recovery. Give it a description that identifies the\nreceiving system and environment without putting credentials or personal data\nin the label. The stored endpoint identifier remains the correlation point for\ndelivery history even if its URL changes later.\n\nKeep test and production receivers separate. Confirm that the URL is the final\nroute that handles the request: **3xx redirects are terminal failures**, so a\nlogin redirect, HTTP-to-HTTPS redirect or trailing-slash rewrite prevents a\nsuccessful delivery.\n\n## Prepare the receiver\n\nBefore adding the endpoint:\n\n- accept the documented POST content type and retain the exact body bytes;\n- read the signature from **x-wildo-webhook-signature**;\n- load the application's published webhook verification key through the\n documented configuration surface;\n- implement atomic deduplication using the signed delivery identifier;\n- queue longer business work instead of performing it before responding;\n- return a small, non-sensitive response body.\n\n~~~mermaid\nsequenceDiagram\n accTitle: Prove a webhook endpoint before production traffic is enabled\n accDescr: An administrator registers a disabled final URL and sends a synthetic signed test. The receiver verifies and deduplicates it, durably accepts the test, responds quickly, and exposes non-secret evidence that the administrator checks before enabling a controlled real event.\n participant Admin as Application administrator\n participant App as Application\n participant Receiver as Your receiver\n participant Queue as Durable queue\n Admin->>App: Save disabled final HTTPS endpoint\n Admin->>App: Send endpoint test\n App->>Receiver: Signed synthetic request\n Receiver->>Receiver: Verify raw bytes, signature and synthetic claim\n Receiver->>Queue: Record safe acceptance\n Receiver-->>App: 2xx with small response\n App-->>Admin: Accepted plus correlation evidence\n Admin->>Receiver: Confirm verification and queue evidence\n Admin->>App: Enable and trigger one controlled real event\n~~~\n\nThe important handoff is between the application outcome and the receiver\nevidence. **Accepted** means a 2xx was observed; it cannot prove which checks the\nreceiver performed internally.\n\n## Register the endpoint safely\n\n1. Select the intended organization or application scope. Do not reuse an\n endpoint configured for another tenant or environment.\n2. Save the final HTTPS URL, a recognizable description and the endpoint in a\n disabled state. A disabled endpoint can still be tested deliberately.\n3. Read the published verification key through the documented application\n configuration surface and pin the expected application environment in the\n receiver.\n4. Confirm the receiver preserves the raw request bytes before any JSON parser,\n proxy rewrite or middleware normalization.\n5. Prepare a durable deduplication record keyed by the signed delivery identity\n and a queue for work that should continue after the response.\n\n## Test before enabling delivery\n\nThe endpoint test uses the same signing and transport path as a real delivery.\nIt can test a disabled endpoint with a synthetic signed payload and does not\ncreate a normal delivery-log row.\n\nInterpret the test outcome precisely:\n\n| Outcome | Meaning | Next action |\n| --- | --- | --- |\n| **Accepted** | Receiver returned a 2xx response | Confirm receiver logs prove signature and body verification occurred before the response |\n| **Rejected** | Receiver returned a non-2xx HTTP response | Inspect receiver validation and response status |\n| **Unreachable** | No HTTP response was obtained | Check public reachability, DNS, TLS and receiver timeout |\n| **Not sent** | Local signing or configuration prevented the request | Correct application configuration before testing the receiver |\n\nRedirect responses are terminal configuration failures. Update the endpoint to\nthe final receiver URL rather than relying on a 3xx hop.\n\nThe synthetic request carries a signed indication that it is a test. Do not\nturn it into a real order, notification or account change. Retain its signed\ndelivery identity long enough to prove that a duplicate test would not repeat\nthe business effect.\n\nRun four checks before enablement:\n\n- a valid signed test is durably accepted and answered with 2xx;\n- a request with a missing or invalid signature is rejected before parsing or\n business processing;\n- a repeated signed delivery identity does not enqueue a second effect;\n- a receiver delay or outage produces a non-success outcome that operators can\n locate in both systems.\n\n## Enable in stages\n\nEnable one endpoint in a non-production organization, trigger one known event\nand verify the complete receiver path. Only then enable broader traffic. Retain\nthe endpoint identity, test time and outcome without retaining the signature or\nsynthetic payload unnecessarily.\n\nFor the first real event, confirm all of the following:\n\n1. the delivery belongs to the intended scope and published event;\n2. signature and raw-body integrity checks ran before the payload was trusted;\n3. the signed delivery identity was claimed exactly once;\n4. the application recorded a successful delivery attempt;\n5. the queued worker produced the intended downstream business result.\n\nIf any check fails, disable the endpoint while preserving the test and delivery\nevidence. Correct the failed boundary, test again while disabled, and repeat one\ncontrolled event before restoring ordinary traffic.\n\n## Retain safe operating evidence\n\nKeep the endpoint's non-secret identifier and description, scope, destination\nhost, test time, outcome, HTTP status, duration and signed delivery identifier\nused for correlation. Do not retain the signature token, verification private\nmaterial, unrestricted payload or sensitive receiver response in an ordinary\nticket.\n\n## Continue safely\n\n- [Verify a webhook delivery](/integrations/webhooks/verify-delivery) for the\n complete receiver-side trust boundary.\n- [Operate webhook deliveries](/integrations/webhooks/operate-deliveries) before\n enabling production volume or automatic recovery.\n- [Troubleshoot webhook deliveries](/integrations/webhooks/troubleshoot) when a\n test or controlled event does not complete.";
397
+ readonly sourceRefs: readonly ["saas-technical-doc:engine-content/configure-and-test-webhook-endpoint", "source:consumer-fact:outbound-webhooks"];
398
+ readonly markdown: "# Configure and test a webhook endpoint\n\nRegister the receiver disabled, prove it with the built-in test, then enable it. This page is shared by the administrator who owns the application's webhook settings and the engineer who owns the receiver; each has half of the evidence.\n\n## Before you register\n\nThe receiver must:\n\n- be reachable from the internet over HTTPS at its final URL. The application does not follow redirects, so an HTTP-to-HTTPS redirect, a login page or a trailing-slash rewrite ends every delivery as failed;\n- not carry credentials in the URL and not resolve to a private or loopback address; such URLs are refused with the `not_sent` outcome;\n- keep the raw request bytes, read the signature from the header and verify it before parsing. [Verify a webhook delivery](/integrations/webhooks/verify-delivery) has a complete receiver you can start from;\n- store the delivery identifier `jti` before doing any work, so a retry cannot repeat the work.\n\n## Register the endpoint\n\n1. Open the webhook settings of the organization (or of the application, for application-wide events).\n2. Copy `applicationPublicKeyPem` from the configuration into your receiver's secret store. This is the key that verifies every signature.\n3. Add an endpoint with the final HTTPS URL and a description that names the receiving system and environment. Leave it **disabled**.\n4. Save. The endpoint's `id` is the identifier every delivery of it will carry; note it.\n\n{{CONSUMER_FACT:source:consumer-fact:outbound-webhooks#endpointMarkdown}}\n\nThe same operations are available to automation through the organization webhook configuration in the [API reference](/api); the endpoint test is its own operation there.\n\n## Run the endpoint test\n\nThe test sends one synthetic, signed request through the same signing and transport path as a real delivery, to the endpoint you choose, even while it is disabled. It does not create a delivery record. Read the outcome precisely:\n\n{{CONSUMER_FACT:source:consumer-fact:outbound-webhooks#testOutcomesMarkdown}}\n\nThe synthetic request is recognisable from its signed claims: `synthetic` is `true` and `operationIdentifier` is `testEndpoint`. Your receiver must verify it like any other request and must not turn it into a business effect; branch on those claims, never on the body text.\n\nBefore enabling, make the receiver pass four cases:\n\n- the test is `accepted`, and the receiver's own log shows verification ran before it answered;\n- a request with a missing or altered signature is refused before the body is parsed;\n- the same `jti` sent twice produces one effect;\n- a receiver that answers slowly produces `unreachable`, and both teams can find that attempt.\n\n## Enable and confirm the first real event\n\nEnable the endpoint, trigger one event you can recognise (for example, invite a test member), and follow it end to end: the delivery row shows `delivered`, the receiver logged the `jti`, and the downstream result exists. Only then let ordinary traffic flow.\n\nIf any step fails, disable the endpoint, keep the delivery and test evidence, fix the one boundary that failed, and repeat the test before re-enabling.\n\n## Change an endpoint later\n\nChanging the URL affects future deliveries only; past delivery rows keep the URL they were sent to. After a URL or receiver deployment change, run the test again and follow one real event before trusting it. Disabling an endpoint stops new deliveries to it; it does not cancel work your receiver already accepted.";
394
399
  }, {
395
400
  readonly managedPath: "integrations/webhooks/verify-delivery.md";
396
401
  readonly unitRef: "technical-documentation:unit/verify-webhook-delivery";
397
- readonly sourceRefs: readonly ["saas-technical-doc:engine-content/verify-webhook-delivery"];
398
- readonly markdown: "# Verify a webhook delivery\n\nTreat every incoming request as untrusted until both the signature token and\nthe exact body bytes have been verified. Parse JSON only after this boundary.\n\nThe signature answers **who signed these exact bytes, for which delivery and\ncontext, and for how long the claim is valid**. It does not decide whether your\nbusiness process should act on the event. Keep cryptographic verification,\ndeduplication, payload validation and business authorization as separate checks.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Load the verification key from the intended application environment, preserve the raw request bytes, define the expected audience and event route, and prepare an atomic store for signed delivery identities | A valid request is trusted and queued once; invalid signatures, changed bytes, unexpected claims, expired tokens and duplicate delivery identities cannot create a business effect |\n\n## Preserve the bytes before parsing\n\nMany web servers parse JSON automatically. Configure the webhook route to retain\nthe exact byte sequence received on the wire before that parser runs. Changing\nwhitespace, character encoding or field order and then serializing the object\nagain produces different bytes and must fail the body-hash check.\n\nRead the signature only from **x-wildo-webhook-signature**. Reject a missing or\nduplicated value according to your HTTP framework's safe header handling; never\naccept a signature copied into the body or query string.\n\n## Verification sequence\n\n1. Read **x-wildo-webhook-signature** and reject a missing or malformed value.\n2. Verify the token with the application's published webhook public key.\n3. Pin **ES256** and validate the expected issuer, audience, key identifier,\n issued time and expiry. Allow only a small, deliberate clock tolerance.\n4. Compute SHA-256 over the **raw request bytes** and compare it with the signed\n body hash using a constant-time comparison.\n5. Validate the signed event channel, resource and operation claims against the\n receiver route you expected.\n6. Atomically claim the signed **jti** before applying a business effect.\n7. Parse and validate the JSON payload against the published event contract.\n\n~~~mermaid\nflowchart TD\n accTitle: Reject a webhook until identity, integrity and replay checks pass\n accDescr: The receiver validates the signature token, recomputes the raw-body hash, checks expected event claims, and atomically claims the jti before parsing and processing the payload.\n request[\"Incoming request\"] --> token{\"Token valid and expected?\"}\n token -->|No| reject[\"Reject without processing\"]\n token -->|Yes| hash{\"Raw-body SHA-256 matches?\"}\n hash -->|No| reject\n hash -->|Yes| claims{\"Event claims expected?\"}\n claims -->|No| reject\n claims -->|Yes| dedup{\"jti claimed atomically?\"}\n dedup -->|Already seen| acknowledge[\"Return the established duplicate outcome\"]\n dedup -->|New| parse[\"Parse, validate and queue work\"]\n~~~\n\n## Know what each signed value proves\n\n| Value | Receiver decision |\n| --- | --- |\n| Signature, algorithm and key identifier | The token was produced by the expected application signing key under the pinned **ES256** algorithm |\n| Issuer and audience | The token belongs to the expected application trust boundary and this receiver purpose |\n| Issued time and expiry | The attempt is within the deliberately accepted time window |\n| Body hash and hash algorithm | The raw bytes received are the bytes that were signed for this attempt |\n| Event channel, resource and operation | The notification belongs on the receiver route and handler selected for it |\n| **jti** | This delivery identity has or has not already been accepted by the receiver |\n\nValidate all required claims as one policy. A correctly signed token for another\nenvironment, audience or event handler is still unacceptable here.\n\nThe body hash identifies bytes; it is not the delivery identity. The token\nstring can also change across contexts. Use **jti** as the deduplication key for\nthe same delivery and keep that claim stable for every retry of its delivery row.\n\nClaim **jti** atomically in the same acceptance boundary that records or queues\nthe work. A separate “check then insert” sequence allows two concurrent attempts\nto pass before either writes the record. Retain the claim for at least as long\nas the delivery can be retried or manually replayed under your operating policy.\n\n## Reject without creating a second vulnerability\n\nReturn a generic non-2xx response for invalid signature, hash or claims. Do not\nexplain which cryptographic comparison failed to an unauthenticated caller, and\ndo not log the complete token or sensitive body. Retain the time, destination\nroute, reason category and non-secret correlation evidence needed for support.\n\nFor a duplicate **jti**, return the stable outcome your receiver design has\nchosen without applying the business effect again. If the first acceptance is\nstill processing, the duplicate must not start parallel work.\n\n## Handle key and deployment changes deliberately\n\nWhen verification starts failing after a deployment or key change, compare the\ntoken's key identifier, issuer and audience with the verification key loaded\nfrom the same application environment. Refresh through the documented key\nsurface; never fetch a key from an untrusted location supplied by the incoming\nrequest. Keep the previous accepted key only when the application's published\nrotation contract explicitly requires an overlap.\n\nTest verification with controlled cases:\n\n- one valid signed delivery reaches the durable queue;\n- one changed raw byte is rejected;\n- one expired or wrong-audience token is rejected;\n- one unexpected event claim is rejected by the route;\n- the same **jti** received concurrently produces one accepted business effect.\n\nDo not weaken algorithm checks, skip expiry or parse and reserialize JSON to\nrepair a verification failure. Those changes remove the security boundary\nrather than diagnosing it.\n\n## Continue safely\n\n- [Configure and test an endpoint](/integrations/webhooks/configure-and-test)\n before enabling a receiver that has not passed the negative cases.\n- [Operate webhook deliveries](/integrations/webhooks/operate-deliveries) to\n separate verified acceptance from longer business work.\n- [Troubleshoot webhook deliveries](/integrations/webhooks/troubleshoot) when\n the application and receiver disagree about the result.";
402
+ readonly sourceRefs: readonly ["saas-technical-doc:engine-content/verify-webhook-delivery", "source:consumer-fact:outbound-webhooks"];
403
+ readonly markdown: "# Verify a webhook delivery\n\nTreat every incoming request as untrusted until the signature and the exact body bytes are verified, then deduplicate on the delivery identifier, and only then parse the body. This page gives the contract and a receiver you can run.\n\n## The signature\n\n{{CONSUMER_FACT:source:consumer-fact:outbound-webhooks#signatureMarkdown}}\n\nA decoded token payload looks like this:\n\n~~~json\n{{CONSUMER_FACT:source:consumer-fact:outbound-webhooks#claimsExampleJson}}\n~~~\n\nThe endpoint test adds `\"synthetic\": true` and sets `operationIdentifier` to `testEndpoint`; treat such a delivery as verified but never act on it.\n\n## The verification sequence\n\n1. Read the signature header. No header, or more than one, is a refusal.\n2. Verify the token with `applicationPublicKeyPem` from the webhook configuration, pinning the algorithm, the issuer and the audience above. Let your JWT library check `exp` and `iat`; allow a few seconds of clock tolerance, not minutes.\n3. Hash the raw request bytes with the algorithm in `bodyHashAlg` and compare the hex digest with `bodyHash` using a constant-time comparison.\n4. Claim `jti` in your durable store atomically with recording the work. A second request with the same `jti` is a retry: answer 2xx and do nothing.\n5. Parse the body and hand it to a queue. Answer the application before the work runs.\n\nRefuse with a plain non-2xx status and no explanation of which check failed. Log the time, the route, the reason category and the `jti`; never the token or the body.\n\n## A receiver in Node.js\n\nExpress and the `jsonwebtoken` package, with the raw body preserved:\n\n~~~javascript\n{{CONSUMER_FACT:source:consumer-fact:outbound-webhooks#verifierSampleNode}}\n~~~\n\n`claimDeliveryOnce` must be an atomic insert keyed by `jti` in the store that also records the work, such as a unique index in a database table, so two concurrent attempts cannot both pass. `enqueue` hands the event to a worker; the response must not wait for the worker.\n\nAny language works the same way: an ES256 JWT verifier with issuer and audience pinned, a SHA-256 over the raw bytes, and a unique key on `jti`.\n\n## Route by claims, not by body\n\nEvery enabled endpoint receives every event on its channel. Use the `resourceIdentifier` and `operationIdentifier` claims to decide which handler runs or whether to ignore the event, before you parse the body. The body is the operation's response document as described in the [API reference](/api) for that resource.\n\n## Prove it before production\n\nRun these five cases against the receiver and keep the results with the endpoint's `id`:\n\n- a valid delivery reaches the queue and is answered 2xx within a second;\n- one changed byte in the body is refused;\n- a token with the wrong audience or an expired `exp` is refused;\n- the same `jti` delivered twice, concurrently, produces one queued job;\n- the endpoint test from the application is `accepted` and is not acted on.\n\n## When keys or deployments change\n\nThe application's webhook key is the one on the configuration. The token header's `kid` is the thumbprint of that key, not a fixed name: a `kid` you have not seen means the key rotated, and the remedy is to reload `applicationPublicKeyPem` from the configuration. If verification still fails, confirm `iss` and `aud` match what your receiver pins. Never disable verification, accept every algorithm, or re-serialise the JSON to make a failing check pass.";
399
404
  }, {
400
405
  readonly managedPath: "integrations/webhooks/operate-deliveries.md";
401
406
  readonly unitRef: "technical-documentation:unit/operate-webhook-deliveries";
402
- readonly sourceRefs: readonly ["saas-technical-doc:engine-content/operate-webhook-deliveries"];
403
- readonly markdown: "# Operate webhook deliveries\n\nWebhook delivery is asynchronous. The application creates one durable delivery\nrow for each enabled endpoint, attempts the request and records the outcome.\nYour receiver should likewise separate safe acceptance from longer business\nprocessing.\n\nOperating webhooks therefore means reconciling **two lifecycles**: delivery from\nthe application to your receiver, and the business work performed after your\nreceiver accepts it. A green delivery does not automatically prove the second\nlifecycle completed.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Assign an owner for the endpoint and receiver queue; define deduplication retention, alert thresholds, downstream reconciliation and the conditions for an explicit retry | Operators can distinguish waiting, active, delivered and terminally failed rows, recover without duplicate effects, and prove the downstream business result separately from HTTP delivery |\n\n## Understand the delivery states\n\n~~~mermaid\nstateDiagram-v2\n accTitle: Webhook delivery lifecycle\n accDescr: A pending delivery becomes in flight. A successful 2xx response marks it delivered. A transient failure schedules another pending attempt, while a terminal failure marks it failed. An administrator can explicitly retry a failed delivery.\n [*] --> Pending\n Pending --> InFlight\n InFlight --> Delivered: 2xx response\n InFlight --> Pending: transient failure and attempts remain\n InFlight --> Failed: terminal failure or attempts exhausted\n Failed --> Pending: explicit retry\n Delivered --> [*]\n~~~\n\nRead each state as an operating instruction:\n\n| State | What it means | What an operator should do |\n| --- | --- | --- |\n| **Pending** | The row is waiting for its first attempt or a scheduled retry | Compare the next-attempt time with the retry schedule; do not start a parallel manual sender |\n| **In flight** | One worker currently holds the delivery for an HTTP attempt | Allow the bounded request to complete; investigate only if the state remains inconsistent with worker health |\n| **Delivered** | The application observed a 2xx response | Confirm the receiver accepted this **jti** durably, then reconcile the downstream result |\n| **Failed** | A terminal response occurred or the attempt budget was exhausted | Correct the failed boundary, prove deduplication, then decide whether an explicit retry is safe |\n\nTransient failures include network failure, timeout, 408, 429 and 5xx. Delivery\nuses at most five attempts with delays of approximately one minute, five\nminutes, thirty minutes and two hours. Each request has a thirty-second timeout.\nRedirects and other terminal 4xx responses are not retried automatically.\n\nThat schedule belongs to the application delivery row. Do not add an immediate\nparallel retry loop at the receiver or an external monitor: it defeats the\nbounded delay, increases load during an outage and can race the same business\neffect.\n\n## Design the receiver for retries\n\n- Claim the signed **jti** atomically before creating the business effect.\n- Return 2xx only after the request is verified and safely accepted.\n- Move slow work to a durable queue.\n- Make downstream processing idempotent as a second line of protection.\n- Reconcile the receiver's accepted deliveries with resulting business records.\n\nThe application records only a bounded response body, currently up to 4 KiB.\nReturn a short diagnostic that contains no credential, personal data or internal\nstack trace. A delivery marked **Delivered** means a 2xx was observed; it does\nnot prove that your asynchronous business work later completed.\n\n## Monitor both sides of acceptance\n\nFor the application delivery lifecycle, monitor:\n\n- pending age and whether the next-attempt time continues to advance;\n- terminal failures by endpoint and response class;\n- a sudden increase in 408, 429 or 5xx outcomes;\n- the attempt count approaching the five-attempt limit;\n- endpoint changes around the first failure time.\n\nFor the receiver lifecycle, monitor:\n\n- signature or body-integrity rejection by reason category;\n- duplicate **jti** claims and whether the existing work is complete;\n- queue age, failed worker jobs and downstream dependency health;\n- accepted deliveries that have no resulting business record;\n- repeated business records that indicate a broken atomic deduplication boundary.\n\nUse the delivery identifier, endpoint identifier, signed **jti**, event context\nand timestamps to join the two views. Do not use the payload body or signature\ntoken as a monitoring label.\n\n## Retry deliberately\n\nAn explicit retry resets a failed delivery for a fresh attempt. Before using it,\nconfirm that the receiver will recognize the same **jti** and that the earlier\nattempt did not already create the business effect.\n\nUse this decision sequence:\n\n1. Read the failed delivery's endpoint snapshot, event context, attempt count,\n response status and failure reason.\n2. Check the receiver using **jti**. Determine whether it never received the\n request, rejected it, accepted it without completing work, or completed the\n business effect despite a lost response.\n3. Correct the actual cause. For a terminal 3xx or 4xx, test the final route or\n verification repair before retrying real traffic.\n4. Confirm that deduplication retention still covers the original **jti** and\n that downstream processing is safe to resume.\n5. Retry one row. Observe the resulting application state and receiver queue\n before retrying a group of failures.\n6. Reconcile the authoritative downstream record and close the incident with\n both delivery and business evidence.\n\nIf the receiver already completed the business effect, do not retry merely to\nturn the delivery row green. Record the mismatch and reconcile it through the\nappropriate operating process.\n\n## Treat endpoint changes as new operating risk\n\nChanging an endpoint URL affects future delivery attempts, while historical\nrows retain the destination snapshot used when they were created. After a URL\nor receiver deployment change, test the configured endpoint, trigger one\ncontrolled event and monitor both delivery and downstream completion before\nrestoring ordinary volume.\n\nDisable an endpoint when the receiver cannot safely accept traffic. Disabling\nstops new matching deliveries from being created for that destination; it is\nnot proof that existing downstream work has been cancelled or reconciled.\n\n## Retain evidence without retaining secrets\n\nKeep the scope, endpoint and delivery identifiers, **jti**, event context,\nattempt count, state transitions, response status, bounded non-sensitive\ndiagnostic and downstream reconciliation result. Apply the organization's\nretention and access policy to payloads because delivery records can contain\nbusiness or personal data.\n\n## Continue safely\n\n- [Troubleshoot webhook deliveries](/integrations/webhooks/troubleshoot) to\n locate the failed boundary before an explicit retry.\n- [Verify a webhook delivery](/integrations/webhooks/verify-delivery) when\n signature, raw-body or duplicate handling is in doubt.\n- Return to [Webhooks](/integrations/webhooks) to review the complete event,\n delivery, attempt and downstream-work model.";
407
+ readonly sourceRefs: readonly ["saas-technical-doc:engine-content/operate-webhook-deliveries", "source:consumer-fact:outbound-webhooks"];
408
+ readonly markdown: "# Operate webhook deliveries\n\nDelivery is asynchronous. For every event the application creates one delivery row per enabled endpoint, attempts the request, and records what came back. Operating webhooks means reading those rows correctly and keeping your receiver's side honest.\n\n## Delivery statuses\n\n{{CONSUMER_FACT:source:consumer-fact:outbound-webhooks#deliveryStatesMarkdown}}\n\nThe delivery log is a resource in the [API reference](/api): list it, search it by status, read one row, or retry a failed one. Each row carries the endpoint `id`, the `httpUrl` it was sent to, `attemptCount`, `nextAttemptAt`, the last `responseStatus`, the first kilobytes of the response body, a `failureReason` when terminal, and `signatureJti`, which is the `jti` your receiver stored.\n\n## The retry ladder\n\n{{CONSUMER_FACT:source:consumer-fact:outbound-webhooks#retryMarkdown}}\n\nThe ladder belongs to the application. Do not add your own immediate retry loop on the receiver side or from a monitor: it defeats the back-off, multiplies load during an outage, and races the same `jti`.\n\n## Design the receiver for retries\n\n- Claim `jti` atomically before any effect; the same `jti` returns on every retry of one delivery.\n- Answer 2xx only after the request is verified and durably queued, and answer well inside the timeout.\n- Do the work in a worker, idempotently, as a second line of defence.\n- Return a short, non-sensitive body; it is recorded on the delivery row and read by operators.\n\nA `delivered` row proves that your receiver answered 2xx. It cannot see whether your worker finished. For anything that moves money or access, reconcile your side against the application with a read.\n\n## Monitor\n\nOn the application side, watch:\n\n- `pending` rows whose `nextAttemptAt` is in the past for longer than a minute: the worker is not draining;\n- `failed` rows by endpoint and `responseStatus`: a burst of one status names one broken boundary;\n- `attemptCount` reaching 4 on many rows: the receiver is slow or flapping;\n- endpoint changes around the first failure time.\n\nOn the receiver side, watch signature rejections by reason, duplicate `jti` claims, queue age and jobs with no downstream record. Join the two views on the endpoint `id`, `signatureJti` and the timestamps; never on the body.\n\n## Retry a failed delivery\n\nThe retry operation re-queues one `failed` row for a fresh attempt with the same `jti` and the same body. Before using it:\n\n1. Read the row: `httpUrl`, `attemptCount`, `responseStatus`, `failureReason`.\n2. Search your receiver's store for the `jti`. Decide whether the receiver never saw it, refused it, accepted it without finishing, or finished the work despite a lost response.\n3. Fix the cause. For a **3xx** or a **4xx** other than 408 and 429, the same bytes would be refused again, so test the endpoint first.\n4. Retry one row and watch it become `delivered`, then retry the rest.\n\nIf the receiver already did the work, do not retry to turn the row green; record the mismatch and reconcile through your own process.\n\n## Endpoint changes and outages\n\nA URL change affects future deliveries; existing rows keep the `httpUrl` they were created with. After any change to the URL or the receiver deployment, run the endpoint test and follow one real event. When the receiver cannot safely accept traffic, disable the endpoint: no new rows are created for it, and rows already `pending` keep retrying until they succeed or run out of attempts.\n\n## Retention\n\nA delivery row stores the full event body it sent, its hash, and the first kilobytes of your receiver's response. Both can contain personal data. Keep responses short, restrict who may read the delivery log, and apply your organization's retention policy to it; the purge operation in the API reference removes old rows.";
404
409
  }, {
405
410
  readonly managedPath: "integrations/webhooks/troubleshoot.md";
406
411
  readonly unitRef: "technical-documentation:unit/troubleshoot-webhook-deliveries";
407
- readonly sourceRefs: readonly ["saas-technical-doc:engine-content/troubleshoot-webhook-deliveries"];
408
- readonly markdown: "# Troubleshoot webhook deliveries\n\nStart from the recorded delivery state, attempt count and HTTP outcome. Do not\ndisable verification or repeatedly change the endpoint while investigating;\nthat removes the evidence needed to find the failed boundary.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Preserve the delivery identifier, endpoint, signed delivery identity, event context, state, attempts, timestamps and HTTP evidence; locate the matching receiver record without copying secrets | The failure is assigned to application signing, transport, receiver verification, safe acceptance or downstream processing; one bounded repair is proven and recovery creates no duplicate effect |\n\n## Locate the first failed boundary\n\n~~~mermaid\nflowchart TD\n accTitle: Locate a webhook failure from application delivery to business result\n accDescr: The operator starts from the delivery record, checks whether a request was sent and answered, then follows receiver verification, atomic acceptance, queued work and authoritative downstream state before deciding whether retry is safe.\n row[\"Preserve delivery and attempt evidence\"] --> sent{\"Request sent?\"}\n sent -->|No| signing[\"Check signing and application configuration\"]\n sent -->|Yes| answered{\"HTTP response received?\"}\n answered -->|No| transport[\"Check final URL, DNS, TLS, reachability and timeout\"]\n answered -->|Yes| success{\"2xx observed?\"}\n success -->|No| receiver[\"Inspect receiver rejection or capacity\"]\n success -->|Yes| claimed{\"jti durably claimed?\"}\n claimed -->|No| acceptance[\"Repair acknowledgement boundary\"]\n claimed -->|Yes| work{\"Business work complete?\"}\n work -->|No| downstream[\"Recover queue or downstream dependency\"]\n work -->|Yes| reconcile[\"Close with delivery and business proof\"]\n~~~\n\nWork from left to right. A later symptom does not erase an earlier failure. For\nexample, manually creating the downstream record can repair the business state,\nbut it does not explain why the receiver returned 2xx before durable acceptance.\n\n## Diagnose by symptom\n\n| Symptom | Likely boundary | What to inspect |\n| --- | --- | --- |\n| Test is **not sent** | Application configuration or signing | Enabled configuration, published key and local error evidence |\n| Test or delivery is **unreachable** | Network, DNS, TLS or receiver availability | Final public URL, certificate, resolved host and receiver timeout |\n| **3xx** response | Endpoint is not the final receiver URL | Configure the redirect destination directly |\n| **400** or **401** from receiver | Signature, claims, body bytes or payload validation | Raw-body capture, signature header, algorithm, key, clock and body hash |\n| **404** from receiver | Wrong route or deployment | Exact configured path and environment |\n| **408**, **429** or **5xx** | Transient receiver failure | Capacity, timeout and retry schedule; do not start a parallel retry loop |\n| Delivery is **Delivered**, but work is missing | Receiver acknowledged before durable acceptance or downstream work failed | Receiver queue, deduplication record and business reconciliation |\n| Repeated business effect | Receiver did not atomically deduplicate **jti** | Deduplication transaction and retention period |\n\n## Investigate without changing several variables\n\n### Nothing was sent\n\nFor **Not sent** or a delivery that failed during signing, check the published\nverification-key configuration and signing evidence for the intended\nenvironment. The receiver cannot repair a request that never left the\napplication. Correct the application-side configuration, then use the endpoint\ntest before retrying real traffic.\n\n### The receiver did not answer\n\nConfirm the configured URL is the final public route. Check DNS, TLS, firewall\nor allow-list rules, deployment health and the receiver's thirty-second request\nwindow. A timeout does not prove the receiver saw nothing: search receiver logs\nand the deduplication store by **jti** before allowing another delivery.\n\n### The receiver answered with non-2xx\n\nPreserve the status and bounded response evidence. For 3xx, configure the final\ndestination directly. For 400 or 401, inspect raw-body capture, the signature\nheader, pinned algorithm, key identifier, clock, audience, event claims and body\nhash. For 404, compare the exact configured route and deployment. For 408, 429\nor 5xx, stabilize receiver capacity and let the scheduled retry proceed unless\nthe delivery has already become terminal.\n\n### Delivery is green but business work is missing\n\nA **Delivered** row proves only that the receiver returned 2xx. Check whether\nthe receiver atomically stored **jti** and durably queued the work before that\nresponse. Then inspect the worker, downstream dependency and authoritative\nbusiness record. Recover the queued job or reconcile the business effect; do not\nretry the application delivery when the receiver already accepted it unless the\nreceiver's deduplication contract makes that recovery deliberate and safe.\n\n### The business effect happened more than once\n\nStop or disable the affected receiver path to contain further duplicates.\nCompare the repeated records with one signed **jti**. Repair the atomic claim and\nwork-enqueue boundary, define how duplicate business records will be reconciled,\nand prove concurrent receipt of the same **jti** creates one effect before\nrestoring traffic.\n\n## Preserve a minimal investigation record\n\nKeep the delivery identifier, endpoint identity, event channel, attempt count,\nstate, response status, timestamps and correlation information. Redact the\nsignature, sensitive payload fields and receiver response content before\nsharing evidence.\n\nIf verification fails after a key or deployment change, compare the key\nidentifier and expected application environment first. Never accept every\nalgorithm or skip body-integrity verification as a fallback.\n\n## Prove and close the repair\n\n1. Test the endpoint while disabled and confirm both the application outcome and\n receiver verification evidence.\n2. Exercise one negative case relevant to the incident—invalid signature,\n changed bytes, duplicate **jti**, receiver timeout or failed downstream work.\n3. Trigger one controlled real event and follow it through delivery, durable\n acceptance and authoritative business state.\n4. Retry one failed delivery only when the earlier effect is absent or safely\n deduplicated.\n5. Record the cause, correction, affected scope, delivery identities and final\n reconciliation without storing secrets or unrestricted payloads.\n\nEscalate with the delivery and endpoint identifiers, **jti**, event context,\nattempt timeline, response class and redacted receiver correlation. Say\nexplicitly whether the receiver may already have accepted or completed the\nwork. That prevents support from treating an ambiguous business outcome as a\nsimple transport retry.\n\n## Continue safely\n\n- [Configure and test an endpoint](/integrations/webhooks/configure-and-test)\n after changing a URL, deployment or signing configuration.\n- [Verify a webhook delivery](/integrations/webhooks/verify-delivery) to repair\n the raw-byte, claim or deduplication boundary.\n- [Operate webhook deliveries](/integrations/webhooks/operate-deliveries) before\n explicit retries or restoring ordinary traffic.";
412
+ readonly sourceRefs: readonly ["saas-technical-doc:engine-content/troubleshoot-webhook-deliveries", "source:consumer-fact:outbound-webhooks"];
413
+ readonly markdown: "# Troubleshoot webhook deliveries\n\nStart from the delivery row. Its status, `attemptCount`, `responseStatus`, `failureReason` and the recorded response body place the failure on one side of the wire. Fix that side, prove it with the endpoint test, then retry the row.\n\n## Find the row\n\nOpen the delivery log for the organization (or the application) and filter by endpoint and time, or search it through the API. The `signatureJti` on the row is the `jti` your receiver logged; it is the key that joins the two systems.\n\n## Diagnose by what the row shows\n\n| Row shows | Where it broke | What to check |\n| --- | --- | --- |\n| No row at all | The event was not published, or webhooks are disabled | The master `enabled` switch, that the endpoint is enabled, and that the operation you performed is one the application publishes |\n| `failed`, `failureReason` mentions signing | The application could not sign | Application-side configuration; nothing on the receiver can help |\n| `failed`, no `responseStatus` | No HTTP answer within the timeout | Public reachability, DNS, TLS, and the receiver's own processing time |\n| `responseStatus` **3xx** | The URL is not the final receiver | Register the redirect target itself; redirects are never followed |\n| `responseStatus` **400** or **401** | Your receiver refused the signature, the body hash or the claims | Raw-body capture, the header name, the pinned algorithm, issuer and audience, the public key, and clock skew |\n| `responseStatus` **404** | Wrong path or wrong deployment | The exact route the receiver serves |\n| `responseStatus` **408**, **429** or **5xx** | The receiver is overloaded or failing | Capacity and errors on the receiver; the row keeps retrying on the ladder |\n| `delivered` but no downstream result | The receiver answered 2xx before durable acceptance, or the worker failed | The receiver's `jti` store, its queue and the worker's errors |\n| The effect happened twice | The receiver did not claim `jti` atomically | The uniqueness constraint on `jti` and the transaction around it |\n\n{{CONSUMER_FACT:source:consumer-fact:outbound-webhooks#retryMarkdown}}\n\n## Signature failures after a change\n\nIf deliveries began failing with **401** right after a deployment or a key change, reload `applicationPublicKeyPem` from the webhook configuration: the token header's `kid` is the thumbprint of the signing key, so a new `kid` means the key rotated. Then confirm `iss` and `aud` still match what the receiver pins. [Verify a webhook delivery](/integrations/webhooks/verify-delivery) lists every pinned value. Do not relax the verifier to make it pass.\n\n## Duplicates\n\nA retry of the same delivery carries the same `jti`; a different delivery of the same operation carries a different one, even when the body is identical. If your effect happened twice with one `jti`, the atomic claim is broken. If it happened twice with two `jti` values, two events really occurred; compare the bodies.\n\n## Prove the repair and retry\n\n1. Run the endpoint test and confirm it is `accepted` with verification logged on the receiver.\n2. Search the receiver's store for the failed row's `jti` to know whether the work already ran.\n3. Retry that one row from the delivery log and watch it become `delivered`.\n4. Retry the remaining failed rows for the same endpoint.\n\n## Ask for help with the right evidence\n\nQuote the endpoint `id`, the delivery row identifier, `signatureJti`, `attemptCount`, `responseStatus`, `failureReason` and the timestamps, and say whether the receiver may already have done the work. Never paste the token or the event body.";
409
414
  }, {
410
415
  readonly managedPath: "integrations/mcp.md";
411
416
  readonly unitRef: "technical-documentation:unit/mcp-integrations";
412
- readonly sourceRefs: readonly ["saas-technical-doc:engine-content/mcp-integrations"];
413
- readonly markdown: "# Connect an MCP client\n\nUse **Model Context Protocol (MCP)** when an AI client should discover a set of\napplication operations as tools and invoke them with structured arguments. The\ntool catalogue is private to the authenticated caller: it is an authorization\nresult, not a universal list of everything the application can do.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Choose the exact application environment, one MCP-capable client, a machine or delegated identity with the MCP audience, one non-production organization and one harmless expected tool | The client authenticates when challenged, receives only its caller-specific catalogue, completes one schema-valid read, refuses an unavailable or unauthorized call and can reconcile an uncertain mutation before retrying |\n\n## Decide who authorizes the client\n\nUse a dedicated machine identity when a service owns the work. Use delegated\nauthorization when a person knowingly lets the client act within their access.\nThe credential must be intended for the selected MCP server audience; an\nordinary REST credential is not automatically valid for this resource server.\n\nDo not place a long-lived machine token in a browser extension, prompt, project\nfile or shared client configuration. Prefer the client's protected credential\nstore and an authorization flow when the client supports one.\n\n## Connect in the right order\n\n~~~mermaid\nsequenceDiagram\n accTitle: Discover and invoke an authorized MCP tool\n accDescr: The client contacts the application MCP server, receives an authentication challenge and protected-resource metadata when it has no credential, discovers the authorization server, obtains a token for this MCP audience, negotiates the supported protocol behavior, lists the caller-specific tools, and invokes one advertised tool with validated arguments.\n participant Client as MCP client\n participant Server as Application MCP server\n participant Auth as Application authorization server\n Client->>Server: Connect without a usable credential\n Server-->>Client: 401 challenge and resource metadata\n Client->>Auth: Discover authorization and request this MCP resource\n Auth-->>Client: Audience-bound access token\n Client->>Server: Negotiate supported protocol behavior\n Client->>Server: tools/list\n Server-->>Client: Caller-specific tool catalogue\n Client->>Server: tools/call with advertised arguments\n Server-->>Client: Result or structured operation error\n~~~\n\nThe authentication challenge is part of a healthy first connection. It tells a\ncompatible client where authorization lives and which protected resource it is\nconnecting to. The resulting token belongs to this MCP server; it is not a\ngeneric credential that should be forwarded to another API.\n\n### Compatibility at a glance\n\n| Client behavior | What this application expects |\n| --- | --- |\n| Remote transport | Streamable HTTP through a desktop, CLI or service MCP host |\n| Authorization discovery | The client follows the protected-resource metadata and authorization-server discovery advertised by the server |\n| Token audience | Authorization is requested for the exact MCP server or named server instance being used |\n| Protocol revision | The client negotiates from the server response and does not force a revision copied from another environment |\n| Server capabilities | Tool discovery and tool invocation; do not assume resources, prompts, sampling or elicitation are available |\n| Catalogue scope | The tool list belongs to the authenticated principal and may legitimately be empty |\n| Browser behavior | A web page must not call the MCP endpoint directly; use an MCP-capable host that protects its credentials |\n\nIf a client can connect only by pasting a bearer token into a project file,\nprompt or browser page, stop and choose a client or authorization setup that can\nprotect the credential. Transport compatibility does not compensate for unsafe\ncredential storage.\n\n### Understand the negotiated revision\n\nThis application currently serves four MCP protocol revisions. The client\nchooses one revision it supports; the server then applies that revision's\nexchange rules. **Do not combine fields from different revisions.**\n\n| Revision | Connection model | What an integration owner needs to know |\n| --- | --- | --- |\n| **2026-07-28** | Stateless discovery and requests | The client discovers the server with **server/discover** and declares the revision in the request metadata and **MCP-Protocol-Version** header. Each request is independently understandable; there is no initialized session to recover. |\n| **2025-11-25** | Initialized session | The client negotiates through **initialize** and completes the initialized notification before ordinary tool calls. |\n| **2025-06-18** | Initialized session | Existing clients keep their revision-specific handshake and are not required to send fields introduced in 2026. |\n| **2025-03-26** | Initialized session | Supported for older clients; prefer a newer revision when the client implements it. |\n\nThe list is ordered newest first, but compatibility is negotiated rather than\nforced. A client that declares an unsupported revision receives the supported\nlist and should retry only with a revision it actually implements.\n\nThe following diagnostic example shows the shape of a current, stateless tool\ncatalogue request. In normal operation, let the MCP client or SDK create these\nheaders and keep the credential in its protected store.\n\n~~~http\nPOST <MCP_SERVER_URL> HTTP/1.1\nAuthorization: Bearer <ACCESS_TOKEN_FOR_THIS_MCP_SERVER>\nContent-Type: application/json\nAccept: application/json, text/event-stream\nMCP-Protocol-Version: 2026-07-28\nMcp-Method: tools/list\n\n{\n \"jsonrpc\": \"2.0\",\n \"id\": \"catalogue-1\",\n \"method\": \"tools/list\",\n \"params\": {\n \"_meta\": {\n \"io.modelcontextprotocol/protocolVersion\": \"2026-07-28\"\n }\n }\n}\n~~~\n\nIf the header and body declare different revisions, correct the client adapter;\ndo not choose whichever value happens to make the request pass. A proxy and the\napplication must interpret the same protocol contract.\n\nConfigure the application server address from this environment's published\nconnection details. If a named MCP server is offered, use its exact address and\nmatching credential audience. Do not copy the URL or server name from another\napplication or environment.\n\nOn first connection:\n\n1. Let the client discover the server and supported protocol behavior.\n2. Complete the authentication challenge for the intended machine or person.\n3. Confirm the displayed server belongs to the expected environment.\n4. List tools and locate one harmless read whose purpose and arguments are\n understandable before invoking it.\n5. Validate the result against the tool's advertised output and the intended\n organization scope.\n6. Attempt one tool that should be unavailable or one action the identity should\n not be allowed to perform. Confirm it remains absent or refused.\n\nUse server discovery and the selected protocol revision instead of hard-coding\nan assumption from another deployment. The application exposes tools only; do\nnot expect MCP resources, prompts, sampling or elicitation unless the published\nserver contract later says otherwise.\n\n## Read the catalogue as an access decision\n\nAn anonymous caller receives no usable tool catalogue. After authentication, a\nmachine identity may see application and organization operations admitted for\nit; a delegated user may additionally see self-service operations. A tool that\nis absent is unavailable to that identity, even if a different user or\nenvironment exposes a similarly named tool.\n\nDo not cache one user's catalogue and reuse it for another identity. Refresh it\nafter a role, organization, credential or application-version change.\n\nRead each descriptor before calling it:\n\n- the tool name identifies the exposed application operation;\n- the description explains its intended outcome and important boundary;\n- the input schema is the contract for structured arguments;\n- collection tools may advertise filters, pagination and sorting supported by\n that operation;\n- absence from the catalogue means the caller must not guess and invoke the\n name directly.\n\nA catalogue descriptor should give the client enough information to build a\nrequest without inventing field names. For example, a collection read may look\nlike this after application-specific names and descriptions have been generated:\n\n~~~json\n{\n \"name\": \"<resource>__list\",\n \"description\": \"List the resources visible to the current caller.\",\n \"inputSchema\": {\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"type\": \"object\",\n \"properties\": {\n \"page\": { \"type\": \"integer\", \"minimum\": 1 },\n \"limit\": { \"type\": \"integer\", \"minimum\": 1 }\n },\n \"additionalProperties\": false\n }\n}\n~~~\n\nThe actual name, description and schema come from this application's published\ncatalogue. The example explains how to read a descriptor; it is not a tool name\nthat every application promises to expose.\n\nTool visibility and callability are evaluated for the same acting principal.\nAn authenticated caller can legitimately receive an empty catalogue. An\nunauthenticated client with no public tools is challenged so it can obtain the\nidentity needed for discovery.\n\n## Prove one useful read\n\nChoose a read that has no business side effect and a result a person can\nrecognize. Ask the client to show the selected tool and structured arguments\nbefore execution. After the call, confirm the returned resource belongs to the\nintended organization and that restricted fields or other organizations are not\npresent.\n\nRetain the server identity, acting principal reference, organization, tool name,\ntime, result class and application correlation evidence. Keep the credential,\ncomplete prompt and sensitive tool result out of ordinary tickets and logs.\n\n## Handle results without unsafe retries\n\nArgument validation and business-rule failures are returned as actionable tool\nerrors. Authentication and authorization failures remain protocol-level access\nerrors so the client can repair authentication instead of treating refusal as\ntool output.\n\nBefore repeating a state-changing call after timeout or transport loss, read\nthe authoritative application state. Limit automatic tool use to the smallest\norganization and role, and require human approval where the operation or your\nown policy identifies material impact.\n\nUse the failure class to choose recovery:\n\n| Observation | Safe response |\n| --- | --- |\n| Authentication challenge or invalid token | Complete or refresh authentication for this server; do not turn the denial into model-visible success text |\n| Tool absent from the catalogue | Verify identity, organization, roles and application publication; do not guess the tool name |\n| Argument validation error | Correct only the rejected structured arguments using the advertised schema |\n| Authorization refusal | Recheck the intended business authority; do not automatically grant a broader role |\n| Conflict or business-rule error | Read current state and adjust the requested outcome |\n| Timeout or lost response from a mutation | Treat the result as ambiguous and reconcile authoritative state before another call |\n\nFor unattended use, bound the call rate, tool set and organization scope. Alert\non repeated authentication failures, authorization refusals, validation loops\nand state-changing calls with no reconciled result.\n\n## Protocol and authorization references\n\n- The current MCP [Streamable HTTP transport](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports)\n reference explains the remote HTTP exchange and its origin-validation\n boundary.\n- The current MCP [authorization specification](https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization)\n explains protected-resource metadata, authorization-server discovery,\n audience binding and the authentication challenge a compatible client uses.\n- The MCP [tools specification](https://modelcontextprotocol.io/specification/2026-07-28/server/tools)\n defines catalogue descriptors, JSON Schema inputs, calls and tool-level error\n results.\n- [RFC 9728](https://www.rfc-editor.org/rfc/rfc9728.html) defines OAuth\n protected-resource metadata, while [RFC 8707](https://www.rfc-editor.org/rfc/rfc8707.html)\n defines the resource indicator used to request a token for the intended\n server.\n\nUse these references to validate the client’s protocol behavior. Use the live\ntool catalogue and this application’s access state to determine which\noperations the current identity can actually invoke.\n\n## Continue safely\n\n- Return to [Agent integrations](/integrations/agents) to compare MCP with an\n A2A conversation or task.\n- [Create your own integration](/integrations/create-your-own-integration) when\n a deterministic REST workflow provides a safer fixed contract.\n- Use [Security and audit](/security-and-audit) to\n investigate protected actions from application evidence rather than the\n conversation transcript.";
417
+ readonly sourceRefs: readonly ["saas-technical-doc:engine-content/mcp-integrations", "source:companion-projection:application-connection", "source:companion-projection:application-integration"];
418
+ readonly markdown: "# Connect an MCP client\n\nUse **Model Context Protocol (MCP)** when an AI client should discover a set of\napplication operations as tools and invoke them with structured arguments. The\ntool catalogue is private to the authenticated caller: it is an authorization\nresult, not a universal list of everything the application can do.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Choose the exact application environment, one MCP-capable client, a machine or delegated identity with the MCP audience, one non-production organization and one harmless expected tool | The client authenticates when challenged, receives only its caller-specific catalogue, completes one schema-valid read, refuses an unavailable or unauthorized call and can reconcile an uncertain mutation before retrying |\n\n## Connect to the endpoint\n\n{{APPLICATION_CONNECTION:mcpEndpoint}}\n\nUse it with the base URL of the environment you chose; the client configuration guides for [Cursor](/integrations/ai-tools/cursor), [Codex](/integrations/ai-tools/codex) and [Claude Code](/integrations/ai-tools/claude-code) show where each tool expects that address.\n\n## The tools this application publishes\n\n{{APPLICATION_INTEGRATION:mcpTools}}\n\n## Decide who authorizes the client\n\nUse a dedicated machine identity when a service owns the work. Use delegated\nauthorization when a person knowingly lets the client act within their access.\nThe credential must be intended for the selected MCP server audience; an\nordinary REST credential is not automatically valid for this resource server.\n\nDo not place a long-lived machine token in a browser extension, prompt, project\nfile or shared client configuration. Prefer the client's protected credential\nstore and an authorization flow when the client supports one.\n\n## Connect in the right order\n\n~~~mermaid\nsequenceDiagram\n accTitle: Discover and invoke an authorized MCP tool\n accDescr: The client contacts the application MCP server, receives an authentication challenge and protected-resource metadata when it has no credential, discovers the authorization server, obtains a token for this MCP audience, negotiates the supported protocol behavior, lists the caller-specific tools, and invokes one advertised tool with validated arguments.\n participant Client as MCP client\n participant Server as Application MCP server\n participant Auth as Application authorization server\n Client->>Server: Connect without a usable credential\n Server-->>Client: 401 challenge and resource metadata\n Client->>Auth: Discover authorization and request this MCP resource\n Auth-->>Client: Audience-bound access token\n Client->>Server: Negotiate supported protocol behavior\n Client->>Server: tools/list\n Server-->>Client: Caller-specific tool catalogue\n Client->>Server: tools/call with advertised arguments\n Server-->>Client: Result or structured operation error\n~~~\n\nThe authentication challenge is part of a healthy first connection. It tells a\ncompatible client where authorization lives and which protected resource it is\nconnecting to. The resulting token belongs to this MCP server; it is not a\ngeneric credential that should be forwarded to another API.\n\n### Compatibility at a glance\n\n| Client behavior | What this application expects |\n| --- | --- |\n| Remote transport | Streamable HTTP through a desktop, CLI or service MCP host |\n| Authorization discovery | The client follows the protected-resource metadata and authorization-server discovery advertised by the server |\n| Token audience | Authorization is requested for the exact MCP server or named server instance being used |\n| Protocol revision | The client negotiates from the server response and does not force a revision copied from another environment |\n| Server capabilities | Tool discovery and tool invocation; do not assume resources, prompts, sampling or elicitation are available |\n| Catalogue scope | The tool list belongs to the authenticated principal and may legitimately be empty |\n| Browser behavior | A web page must not call the MCP endpoint directly; use an MCP-capable host that protects its credentials |\n\nIf a client can connect only by pasting a bearer token into a project file,\nprompt or browser page, stop and choose a client or authorization setup that can\nprotect the credential. Transport compatibility does not compensate for unsafe\ncredential storage.\n\n### Understand the negotiated revision\n\nThis application currently serves four MCP protocol revisions. The client\nchooses one revision it supports; the server then applies that revision's\nexchange rules. **Do not combine fields from different revisions.**\n\n| Revision | Connection model | What an integration owner needs to know |\n| --- | --- | --- |\n| **2026-07-28** | Stateless discovery and requests | The client discovers the server with **server/discover** and declares the revision in the request metadata and **MCP-Protocol-Version** header. Each request is independently understandable; there is no initialized session to recover. |\n| **2025-11-25** | Initialized session | The client negotiates through **initialize** and completes the initialized notification before ordinary tool calls. |\n| **2025-06-18** | Initialized session | Existing clients keep their revision-specific handshake and are not required to send fields introduced in 2026. |\n| **2025-03-26** | Initialized session | Supported for older clients; prefer a newer revision when the client implements it. |\n\nThe list is ordered newest first, but compatibility is negotiated rather than\nforced. A client that declares an unsupported revision receives the supported\nlist and should retry only with a revision it actually implements.\n\nThe following diagnostic example shows the shape of a current, stateless tool\ncatalogue request. In normal operation, let the MCP client or SDK create these\nheaders and keep the credential in its protected store.\n\n~~~http\nPOST {{APPLICATION_CONNECTION_VALUE:mcpEndpointUrl}} HTTP/1.1\nAuthorization: Bearer <ACCESS_TOKEN_FOR_THIS_MCP_SERVER>\nContent-Type: application/json\nAccept: application/json, text/event-stream\nMCP-Protocol-Version: 2026-07-28\nMcp-Method: tools/list\n\n{\n \"jsonrpc\": \"2.0\",\n \"id\": \"catalogue-1\",\n \"method\": \"tools/list\",\n \"params\": {\n \"_meta\": {\n \"io.modelcontextprotocol/protocolVersion\": \"2026-07-28\"\n }\n }\n}\n~~~\n\nIf the header and body declare different revisions, correct the client adapter;\ndo not choose whichever value happens to make the request pass. A proxy and the\napplication must interpret the same protocol contract.\n\nConfigure the application server address from this environment's published\nconnection details. If a named MCP server is offered, use its exact address and\nmatching credential audience. Do not copy the URL or server name from another\napplication or environment.\n\nOn first connection:\n\n1. Let the client discover the server and supported protocol behavior.\n2. Complete the authentication challenge for the intended machine or person.\n3. Confirm the displayed server belongs to the expected environment.\n4. List tools and locate one harmless read whose purpose and arguments are\n understandable before invoking it.\n5. Validate the result against the tool's advertised output and the intended\n organization scope.\n6. Attempt one tool that should be unavailable or one action the identity should\n not be allowed to perform. Confirm it remains absent or refused.\n\nUse server discovery and the selected protocol revision instead of hard-coding\nan assumption from another deployment. The application exposes tools only; do\nnot expect MCP resources, prompts, sampling or elicitation unless the published\nserver contract later says otherwise.\n\n## Read the catalogue as an access decision\n\nAn anonymous caller receives no usable tool catalogue. After authentication, a\nmachine identity may see application and organization operations admitted for\nit; a delegated user may additionally see self-service operations. A tool that\nis absent is unavailable to that identity, even if a different user or\nenvironment exposes a similarly named tool.\n\nDo not cache one user's catalogue and reuse it for another identity. Refresh it\nafter a role, organization, credential or application-version change.\n\nRead each descriptor before calling it:\n\n- the tool name identifies the exposed application operation;\n- the description explains its intended outcome and important boundary;\n- the input schema is the contract for structured arguments;\n- collection tools may advertise filters, pagination and sorting supported by\n that operation;\n- absence from the catalogue means the caller must not guess and invoke the\n name directly.\n\nA catalogue descriptor should give the client enough information to build a\nrequest without inventing field names. For example, a collection read may look\nlike this after application-specific names and descriptions have been generated:\n\n~~~json\n{\n \"name\": \"<resource>__list\",\n \"description\": \"List the resources visible to the current caller.\",\n \"inputSchema\": {\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"type\": \"object\",\n \"properties\": {\n \"page\": { \"type\": \"integer\", \"minimum\": 1 },\n \"limit\": { \"type\": \"integer\", \"minimum\": 1 }\n },\n \"additionalProperties\": false\n }\n}\n~~~\n\nThe actual name, description and schema come from this application's published\ncatalogue. The example explains how to read a descriptor; it is not a tool name\nthat every application promises to expose.\n\nTool visibility and callability are evaluated for the same acting principal.\nAn authenticated caller can legitimately receive an empty catalogue. An\nunauthenticated client with no public tools is challenged so it can obtain the\nidentity needed for discovery.\n\n## Prove one useful read\n\nChoose a read that has no business side effect and a result a person can\nrecognize. Ask the client to show the selected tool and structured arguments\nbefore execution. After the call, confirm the returned resource belongs to the\nintended organization and that restricted fields or other organizations are not\npresent.\n\nRetain the server identity, acting principal reference, organization, tool name,\ntime, result class and application correlation evidence. Keep the credential,\ncomplete prompt and sensitive tool result out of ordinary tickets and logs.\n\n## Handle results without unsafe retries\n\nArgument validation and business-rule failures are returned as actionable tool\nerrors. Authentication and authorization failures remain protocol-level access\nerrors so the client can repair authentication instead of treating refusal as\ntool output.\n\nBefore repeating a state-changing call after timeout or transport loss, read\nthe authoritative application state. Limit automatic tool use to the smallest\norganization and role, and require human approval where the operation or your\nown policy identifies material impact.\n\nUse the failure class to choose recovery:\n\n| Observation | Safe response |\n| --- | --- |\n| Authentication challenge or invalid token | Complete or refresh authentication for this server; do not turn the denial into model-visible success text |\n| Tool absent from the catalogue | Verify identity, organization, roles and application publication; do not guess the tool name |\n| Argument validation error | Correct only the rejected structured arguments using the advertised schema |\n| Authorization refusal | Recheck the intended business authority; do not automatically grant a broader role |\n| Conflict or business-rule error | Read current state and adjust the requested outcome |\n| Timeout or lost response from a mutation | Treat the result as ambiguous and reconcile authoritative state before another call |\n\nFor unattended use, bound the call rate, tool set and organization scope. Alert\non repeated authentication failures, authorization refusals, validation loops\nand state-changing calls with no reconciled result.\n\n## Protocol and authorization references\n\n- The current MCP [Streamable HTTP transport](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports)\n reference explains the remote HTTP exchange and its origin-validation\n boundary.\n- The current MCP [authorization specification](https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization)\n explains protected-resource metadata, authorization-server discovery,\n audience binding and the authentication challenge a compatible client uses.\n- The MCP [tools specification](https://modelcontextprotocol.io/specification/2026-07-28/server/tools)\n defines catalogue descriptors, JSON Schema inputs, calls and tool-level error\n results.\n- [RFC 9728](https://www.rfc-editor.org/rfc/rfc9728.html) defines OAuth\n protected-resource metadata, while [RFC 8707](https://www.rfc-editor.org/rfc/rfc8707.html)\n defines the resource indicator used to request a token for the intended\n server.\n\nUse these references to validate the client’s protocol behavior. Use the live\ntool catalogue and this application’s access state to determine which\noperations the current identity can actually invoke.\n\n## Continue safely\n\n- Return to [Agent integrations](/integrations/agents) to compare MCP with an\n A2A conversation or task.\n- [Create your own integration](/integrations/create-your-own-integration) when\n a deterministic REST workflow provides a safer fixed contract.\n- Use [Security and audit](/security-and-audit) to\n investigate protected actions from application evidence rather than the\n conversation transcript.";
414
419
  }, {
415
420
  readonly managedPath: "integrations/a2a.md";
416
421
  readonly unitRef: "technical-documentation:unit/a2a-integrations";
417
- readonly sourceRefs: readonly ["saas-technical-doc:engine-content/a2a-integrations"];
418
- readonly markdown: "# Connect an A2A agent\n\nUse **Agent-to-Agent (A2A)** when another agent should exchange messages with\nthis application and track work that may continue beyond one response. Start\nfrom the published agent card. It identifies the agent instance, declared\nskills and supported interaction contract; do not infer those details from an\nMCP catalogue.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Choose one published agent, one declared skill, the intended machine or delegated identity, one non-production organization and whether the work should complete in the response or continue as a task | One text message reaches the intended agent, the caller preserves conversation and task correlation, unauthorized task access remains indistinguishable from absence, and cancellation or resumed monitoring reports the real terminal outcome |\n\n## Read the agent card before sending work\n\nThe public card describes the selected agent and the skills this application\npublishes for it. Confirm the card belongs to the intended environment and named\nagent instance. Treat it as discovery metadata: task and message operations\nstill require a Bearer credential whose audience matches that agent.\n\nChoose one skill whose purpose and expected result are understandable. The\ncurrent application transport consumes text message parts; do not attach files,\nimages or other part types and assume they will be used. A message with no\nusable text is refused.\n\n## Choose the protocol interface the card advertises\n\nThe current agent card deliberately serves two A2A dialects on the same JSON-RPC\nURL. A current client reads the ordered `supportedInterfaces` list and should\nprefer its first compatible entry, **A2A 1.0**. A legacy client can continue to\nread `protocolVersion: 0.2.5` and the legacy URL field.\n\n~~~mermaid\nflowchart TD\n accTitle: Select one advertised A2A interface without mixing dialects\n accDescr: A client loads the agent card, checks the ordered supported interfaces, selects the first JSON-RPC protocol version it implements, binds authorization to that interface URL, and then uses only the method names, request fields and task states belonging to the selected dialect. A legacy client that cannot read supported interfaces uses the card's 0.2.5 fields.\n card[\"Load the intended agent card\"] --> modern{\"Client reads supportedInterfaces?\"}\n modern -->|\"Yes\"| select[\"Select first compatible JSONRPC interface\"]\n modern -->|\"No\"| legacy[\"Use legacy protocolVersion 0.2.5 fields\"]\n select --> audience[\"Request authorization for selected interface URL\"]\n legacy --> audience\n audience --> dialect[\"Use one dialect's methods, fields and task states\"]\n dialect --> proof[\"Prove one message and task lifecycle\"]\n~~~\n\n| Card or request concern | Correct behavior |\n| --- | --- |\n| Preferred interface | Select the first compatible entry from `supportedInterfaces`; the card currently orders 1.0 before 0.2.5 |\n| Legacy compatibility | A client that only understands the scalar `protocolVersion` can continue with 0.2.5 |\n| Endpoint and audience | Use the URL from the selected interface and obtain a token intended for that exact agent |\n| Method vocabulary | Use the JSON-RPC method names belonging to the selected dialect; do not mix 1.0 and legacy names in one integration |\n| Non-blocking work | A2A 1.0 uses its return-immediately field; the legacy dialect uses `configuration.blocking: false` |\n| Task state values | Parse the state vocabulary returned for the selected dialect instead of hard-coding values observed from another client |\n\n> **Do not “upgrade” only one field.** Changing a version value while continuing\n> to send the other dialect’s method names, task states or execution flag creates\n> a request that no published interface describes. Let an A2A SDK or a single\n> reviewed adapter own the dialect translation.\n\n### Read the card as a live contract\n\nThe card is generated for the selected application environment and agent\ninstance. Its concrete names, URL and skill list vary, but its structure is\nsimilar to this redacted example:\n\n~~~json\n{\n \"protocolVersion\": \"0.2.5\",\n \"supportedInterfaces\": [\n { \"url\": \"<APPLICATION_AGENT_URL>\", \"transport\": \"JSONRPC\", \"version\": \"1.0\" },\n { \"url\": \"<APPLICATION_AGENT_URL>\", \"transport\": \"JSONRPC\", \"version\": \"0.2.5\" }\n ],\n \"name\": \"<APPLICATION_AGENT_NAME>\",\n \"capabilities\": {\n \"streaming\": true,\n \"pushNotifications\": true\n },\n \"defaultInputModes\": [\"text/plain\"],\n \"defaultOutputModes\": [\"text/markdown\"],\n \"skills\": [\n {\n \"id\": \"<APPLICATION_SKILL_REFERENCE>\",\n \"name\": \"<APPLICATION_SKILL_NAME>\",\n \"description\": \"<WHAT_THIS_SKILL_DOES>\"\n }\n ]\n}\n~~~\n\nThe scalar **protocolVersion** remains **0.2.5** for older clients. A current\nclient reads the ordered **supportedInterfaces** array and prefers **1.0**. Both\nentries point to the same endpoint: the JSON-RPC method name identifies the\ndialect.\n\n### Keep method names in one dialect\n\n| Operation | A2A 1.0 JSON-RPC method | A2A 0.2.5 JSON-RPC method |\n| --- | --- | --- |\n| Send a message | **SendMessage** | **message/send** |\n| Stream a message | **SendStreamingMessage** | **message/stream** |\n| Read a task | **GetTask** | **tasks/get** |\n| Cancel a task | **CancelTask** | **tasks/cancel** |\n| Resume task streaming | **SubscribeToTask** | **tasks/resubscribe** |\n| Create a push target | **CreateTaskPushNotificationConfig** | **tasks/pushNotificationConfig/set** |\n| Read a push target | **GetTaskPushNotificationConfig** | **tasks/pushNotificationConfig/get** |\n| List push targets | **ListTaskPushNotificationConfigs** | **tasks/pushNotificationConfig/list** |\n| Delete a push target | **DeleteTaskPushNotificationConfig** | **tasks/pushNotificationConfig/delete** |\n| List the caller's tasks | **ListTasks** | Not defined |\n| Request an extended card | **GetExtendedAgentCard** | Not defined; this application refuses it because the card does not advertise one |\n\nHere is a minimal A2A 1.0 request for work that should return a task immediately.\nUse the skill identifier from the live card; never substitute the display name.\n\n~~~json\n{\n \"jsonrpc\": \"2.0\",\n \"id\": \"turn-1\",\n \"method\": \"SendMessage\",\n \"params\": {\n \"return_immediately\": true,\n \"message\": {\n \"role\": \"user\",\n \"parts\": [\n { \"kind\": \"text\", \"text\": \"Summarize the open items assigned to my team.\" }\n ],\n \"metadata\": {\n \"skillId\": \"<APPLICATION_SKILL_REFERENCE>\"\n }\n }\n }\n}\n~~~\n\nFor a 0.2.5 request, use **message/send** and place **blocking: false**\ninside **params.configuration**. Do not rename the method while retaining the\nother dialect's non-blocking field.\n\n## Choose a response or a task\n\nA message may wait for an immediate result or explicitly create non-blocking\nwork. For longer work, retain the returned task identity and monitor its state.\nStreaming uses server-sent events when the published contract supports it.\n\nUse immediate completion for short, bounded work where the client can safely\nhold the connection. Use a task when the work may take longer, pause for human\napproval, need cancellation or require later status checks. Decide before\nsending the message; do not treat a client timeout as permission to create the\nsame task again.\n\n~~~mermaid\nstateDiagram-v2\n accTitle: Correlate an A2A conversation and task\n accDescr: A caller sends a text message in a conversation context. Work may complete immediately or create a task. The caller can read, stream, cancel, or resume that task while keeping the same agent instance and authorization context.\n [*] --> MessageSent\n MessageSent --> ImmediateResult: blocking completion\n MessageSent --> Working: task created\n Working --> AwaitingApproval: high-impact action requires approval\n AwaitingApproval --> Working: approved\n Working --> Completed\n Working --> Failed\n Working --> Cancelled: authorized cancellation\n ImmediateResult --> [*]\n Completed --> [*]\n Failed --> [*]\n Cancelled --> [*]\n~~~\n\nThe important distinction is between **contextId** and the task identifier.\nThe context threads related conversational turns. The task identifier addresses\none materialized unit of work. Preserve both when the response creates a task.\n\nUse **contextId** to continue a conversation. Preserve the task identifier for\ntask reads, cancellation and stream resubscription. A message cannot currently\nattach itself to an existing task identifier; treat conversation correlation\nand task correlation as separate fields.\n\n### Interpret every task state deliberately\n\nThe application uses one internal lifecycle and projects it into the selected\nA2A dialect. A 1.0 client receives **TASK_STATE_*** values; a 0.2.5 client\nreceives lowercase, hyphenated values.\n\n| Meaning | A2A 1.0 value | A2A 0.2.5 value | Current application behavior |\n| --- | --- | --- | --- |\n| Accepted, not yet processing | **TASK_STATE_SUBMITTED** | **submitted** | Emitted for queued work |\n| Actively processing | **TASK_STATE_WORKING** | **working** | Emitted while the turn runs |\n| Waiting for a person | **TASK_STATE_INPUT_REQUIRED** | **input-required** | Emitted when a delegated user's approval-gated action pauses; retain this task and answer the pending decision |\n| Additional authentication required | **TASK_STATE_AUTH_REQUIRED** | **auth-required** | Protocol value understood, but not emitted by this application |\n| Completed successfully | **TASK_STATE_COMPLETED** | **completed** | Emitted as a terminal outcome |\n| Failed | **TASK_STATE_FAILED** | **failed** | Emitted as a terminal outcome, including abandoned execution recovery |\n| Cancelled | **TASK_STATE_CANCELED** | **canceled** | Emitted only when cancellation becomes the task outcome |\n| Rejected by the agent | **TASK_STATE_REJECTED** | **rejected** | Protocol value understood, but not emitted by this application |\n| State cannot be determined | **TASK_STATE_UNKNOWN** | **unknown** | Protocol value understood, but not emitted; an inaccessible task is reported as not found instead |\n\n**Input required is not a failure.** For a delegated user, it means the exact\nexecution has paused at an approval boundary. A machine principal cannot supply\nhuman approval, so the same protected action is denied instead of being parked\nindefinitely.\n\n## Complete one controlled exchange\n\n1. Load the selected agent card and record its environment, agent identity and\n chosen skill.\n2. Authenticate with a credential issued for that agent audience and the\n intended acting principal.\n3. Send one short text request in a non-production organization. State the\n desired result and boundaries rather than embedding credentials or large\n application records in the message.\n4. If the response completes immediately, validate its content and confirm any\n claimed application change against authoritative state.\n5. If a task is returned, store its task identifier, **contextId**, agent\n instance and acting identity together. Poll or stream using the same\n authorization context.\n6. Exercise one refused cross-identity or cross-agent task read. It should not\n reveal whether another caller's task exists.\n\n## Respect identity and ownership\n\nThe public agent card is metadata. Task operations require a Bearer credential\nwhose audience matches the selected agent. A delegated user or machine identity\nstill faces application roles, organization scope and per-operation policy.\nAnother caller's task is intentionally indistinguishable from a missing task.\n\nNamed agent instances have their own card, audience and skill subset. Keep the\nagent instance, task, conversation context and credential aligned throughout\nthe exchange.\n\nIf a task pauses for approval, present the proposed impact to the authorized\nperson and retain the pending task identity. Approval resumes that exact work;\nstarting a new conversation is not equivalent. If the work is no longer\nacceptable, cancel the task rather than approving and attempting to reverse it\nlater.\n\nCancellation is an outcome, not merely a request. Read the task after the\ncancellation attempt and distinguish a task that became cancelled from one that\nhad already completed or failed. Do not report success when cancellation was\nrefused because the task was terminal.\n\n## Operate within the published limits\n\nOnly text message parts are currently consumed; a message with no usable text\nfails. Turn rate limits and organization token budgets are different controls: a 429\nrequires pacing, while a 402 requires budget or entitlement resolution. A\nhigh-impact action may pause for explicit approval rather than fail.\n\nHandle these observations separately:\n\n- **429 rate limited:** stop parallel turns and follow the indicated delay;\n- **402 budget exceeded:** waiting briefly will not restore entitlement—resolve\n the applicable allowance or plan;\n- **task not found:** verify the caller, agent instance and task identifier, while\n preserving the intentional no-disclosure boundary for another caller's task;\n- **working with no live execution:** continue reading the task; the application\n reports abandoned work as failed rather than leaving it indefinitely active;\n- **input required:** keep the task identity and complete the required approval\n or input through the supported continuation path;\n- **terminal task:** do not cancel or resume it as if it were still active.\n\nFor asynchronous operation, choose polling, streaming or configured push\nnotification only when the published agent contract supports it. Treat a push\nnotification as a signal to read the task's authoritative state, and process\nnotifications idempotently.\n\nTreat every returned message and artifact as untrusted input. Retain correlation\nand outcome evidence, redact prompts and results before export, and use the\napplication's audit trail as the authoritative record of protected actions.\n\n## Close the task with proof\n\nRecord the environment, agent instance, skill, acting identity reference,\norganization, **contextId**, task identifier, state timeline and non-sensitive\ncorrelation evidence. Confirm the final application resource or external effect\ninstead of relying only on the agent's final message.\n\nIf the connection fails after submission, read the task under the original\nidentity before sending another message. Create new work only when the original\ntask is absent or terminal in a state that makes repetition deliberate and safe.\n\n## Protocol references for client implementers\n\n- The official [A2A 1.0 specification](https://a2a-protocol.org/latest/specification/)\n defines agent discovery, supported interfaces, messages, task lifecycle and\n the JSON-RPC binding.\n- [What changed in A2A 1.0](https://a2a-protocol.org/latest/whats-new-v1/)\n explains the move from scalar card transport/version fields to the ordered\n `supportedInterfaces` model.\n- The maintained [A2A protocol definitions](https://a2a-protocol.org/latest/definitions/)\n provide machine-readable schemas for clients and conformance tests.\n- [RFC 8707](https://www.rfc-editor.org/rfc/rfc8707.html) defines the resource\n indicator used to bind authorization to the selected agent audience.\n\nUse the specification to implement the chosen dialect, then use the live agent\ncard as the authority for this application’s URL, supported interfaces,\ncapabilities and skill inventory.\n\n## Continue safely\n\n- Return to [Agent integrations](/integrations/agents) to compare A2A with a\n structured MCP tool call.\n- **Connect an MCP client** — published in this section when the application\n exposes an MCP tool surface — when the desired work is a known application\n operation with an immediate structured result.\n- Use [Security and audit](/security-and-audit) to\n investigate protected actions independently of model output.";
422
+ readonly sourceRefs: readonly ["saas-technical-doc:engine-content/a2a-integrations", "source:companion-projection:application-connection"];
423
+ readonly markdown: "# Connect an A2A agent\n\nUse **Agent-to-Agent (A2A)** when another agent should exchange messages with\nthis application and track work that may continue beyond one response. Start\nfrom the published agent card. It identifies the agent instance, declared\nskills and supported interaction contract; do not infer those details from an\nMCP catalogue.\n\n| Before you begin | Successful result |\n| --- | --- |\n| Choose one published agent, one declared skill, the intended machine or delegated identity, one non-production organization and whether the work should complete in the response or continue as a task | One text message reaches the intended agent, the caller preserves conversation and task correlation, unauthorized task access remains indistinguishable from absence, and cancellation or resumed monitoring reports the real terminal outcome |\n\n## Read the agent card before sending work\n\n{{APPLICATION_CONNECTION:a2aAgentCard}}\n\nThe public card describes the selected agent and the skills this application\npublishes for it. Confirm the card belongs to the intended environment and named\nagent instance. Treat it as discovery metadata: task and message operations\nstill require a Bearer credential whose audience matches that agent.\n\nChoose one skill whose purpose and expected result are understandable. The\ncurrent application transport consumes text message parts; do not attach files,\nimages or other part types and assume they will be used. A message with no\nusable text is refused.\n\n## Choose the protocol interface the card advertises\n\nThe current agent card deliberately serves two A2A dialects on the same JSON-RPC\nURL. A current client reads the ordered `supportedInterfaces` list and should\nprefer its first compatible entry, **A2A 1.0**. A legacy client can continue to\nread `protocolVersion: 0.2.5` and the legacy URL field.\n\n~~~mermaid\nflowchart TD\n accTitle: Select one advertised A2A interface without mixing dialects\n accDescr: A client loads the agent card, checks the ordered supported interfaces, selects the first JSON-RPC protocol version it implements, binds authorization to that interface URL, and then uses only the method names, request fields and task states belonging to the selected dialect. A legacy client that cannot read supported interfaces uses the card's 0.2.5 fields.\n card[\"Load the intended agent card\"] --> modern{\"Client reads supportedInterfaces?\"}\n modern -->|\"Yes\"| select[\"Select first compatible JSONRPC interface\"]\n modern -->|\"No\"| legacy[\"Use legacy protocolVersion 0.2.5 fields\"]\n select --> audience[\"Request authorization for selected interface URL\"]\n legacy --> audience\n audience --> dialect[\"Use one dialect's methods, fields and task states\"]\n dialect --> proof[\"Prove one message and task lifecycle\"]\n~~~\n\n| Card or request concern | Correct behavior |\n| --- | --- |\n| Preferred interface | Select the first compatible entry from `supportedInterfaces`; the card currently orders 1.0 before 0.2.5 |\n| Legacy compatibility | A client that only understands the scalar `protocolVersion` can continue with 0.2.5 |\n| Endpoint and audience | Use the URL from the selected interface and obtain a token intended for that exact agent |\n| Method vocabulary | Use the JSON-RPC method names belonging to the selected dialect; do not mix 1.0 and legacy names in one integration |\n| Non-blocking work | A2A 1.0 uses its return-immediately field; the legacy dialect uses `configuration.blocking: false` |\n| Task state values | Parse the state vocabulary returned for the selected dialect instead of hard-coding values observed from another client |\n\n> **Do not “upgrade” only one field.** Changing a version value while continuing\n> to send the other dialect’s method names, task states or execution flag creates\n> a request that no published interface describes. Let an A2A SDK or a single\n> reviewed adapter own the dialect translation.\n\n### Read the card as a live contract\n\nThe card is generated for the selected application environment and agent\ninstance. Its concrete names, URL and skill list vary, but its structure is\nsimilar to this redacted example:\n\n~~~json\n{\n \"protocolVersion\": \"0.2.5\",\n \"supportedInterfaces\": [\n { \"url\": \"{{APPLICATION_CONNECTION_VALUE:agentCardUrl}}\", \"transport\": \"JSONRPC\", \"version\": \"1.0\" },\n { \"url\": \"{{APPLICATION_CONNECTION_VALUE:agentCardUrl}}\", \"transport\": \"JSONRPC\", \"version\": \"0.2.5\" }\n ],\n \"name\": \"<APPLICATION_AGENT_NAME>\",\n \"capabilities\": {\n \"streaming\": true,\n \"pushNotifications\": true\n },\n \"defaultInputModes\": [\"text/plain\"],\n \"defaultOutputModes\": [\"text/markdown\"],\n \"skills\": [\n {\n \"id\": \"<APPLICATION_SKILL_REFERENCE>\",\n \"name\": \"<APPLICATION_SKILL_NAME>\",\n \"description\": \"<WHAT_THIS_SKILL_DOES>\"\n }\n ]\n}\n~~~\n\nThe scalar **protocolVersion** remains **0.2.5** for older clients. A current\nclient reads the ordered **supportedInterfaces** array and prefers **1.0**. Both\nentries point to the same endpoint: the JSON-RPC method name identifies the\ndialect.\n\n### Keep method names in one dialect\n\n| Operation | A2A 1.0 JSON-RPC method | A2A 0.2.5 JSON-RPC method |\n| --- | --- | --- |\n| Send a message | **SendMessage** | **message/send** |\n| Stream a message | **SendStreamingMessage** | **message/stream** |\n| Read a task | **GetTask** | **tasks/get** |\n| Cancel a task | **CancelTask** | **tasks/cancel** |\n| Resume task streaming | **SubscribeToTask** | **tasks/resubscribe** |\n| Create a push target | **CreateTaskPushNotificationConfig** | **tasks/pushNotificationConfig/set** |\n| Read a push target | **GetTaskPushNotificationConfig** | **tasks/pushNotificationConfig/get** |\n| List push targets | **ListTaskPushNotificationConfigs** | **tasks/pushNotificationConfig/list** |\n| Delete a push target | **DeleteTaskPushNotificationConfig** | **tasks/pushNotificationConfig/delete** |\n| List the caller's tasks | **ListTasks** | Not defined |\n| Request an extended card | **GetExtendedAgentCard** | Not defined; this application refuses it because the card does not advertise one |\n\nHere is a minimal A2A 1.0 request for work that should return a task immediately.\nUse the skill identifier from the live card; never substitute the display name.\n\n~~~json\n{\n \"jsonrpc\": \"2.0\",\n \"id\": \"turn-1\",\n \"method\": \"SendMessage\",\n \"params\": {\n \"return_immediately\": true,\n \"message\": {\n \"role\": \"user\",\n \"parts\": [\n { \"kind\": \"text\", \"text\": \"Summarize the open items assigned to my team.\" }\n ],\n \"metadata\": {\n \"skillId\": \"<APPLICATION_SKILL_REFERENCE>\"\n }\n }\n }\n}\n~~~\n\nFor a 0.2.5 request, use **message/send** and place **blocking: false**\ninside **params.configuration**. Do not rename the method while retaining the\nother dialect's non-blocking field.\n\n## Choose a response or a task\n\nA message may wait for an immediate result or explicitly create non-blocking\nwork. For longer work, retain the returned task identity and monitor its state.\nStreaming uses server-sent events when the published contract supports it.\n\nUse immediate completion for short, bounded work where the client can safely\nhold the connection. Use a task when the work may take longer, pause for human\napproval, need cancellation or require later status checks. Decide before\nsending the message; do not treat a client timeout as permission to create the\nsame task again.\n\n~~~mermaid\nstateDiagram-v2\n accTitle: Correlate an A2A conversation and task\n accDescr: A caller sends a text message in a conversation context. Work may complete immediately or create a task. The caller can read, stream, cancel, or resume that task while keeping the same agent instance and authorization context.\n [*] --> MessageSent\n MessageSent --> ImmediateResult: blocking completion\n MessageSent --> Working: task created\n Working --> AwaitingApproval: high-impact action requires approval\n AwaitingApproval --> Working: approved\n Working --> Completed\n Working --> Failed\n Working --> Cancelled: authorized cancellation\n ImmediateResult --> [*]\n Completed --> [*]\n Failed --> [*]\n Cancelled --> [*]\n~~~\n\nThe important distinction is between **contextId** and the task identifier.\nThe context threads related conversational turns. The task identifier addresses\none materialized unit of work. Preserve both when the response creates a task.\n\nUse **contextId** to continue a conversation. Preserve the task identifier for\ntask reads, cancellation and stream resubscription. A message cannot currently\nattach itself to an existing task identifier; treat conversation correlation\nand task correlation as separate fields.\n\n### Interpret every task state deliberately\n\nThe application uses one internal lifecycle and projects it into the selected\nA2A dialect. A 1.0 client receives **TASK_STATE_*** values; a 0.2.5 client\nreceives lowercase, hyphenated values.\n\n| Meaning | A2A 1.0 value | A2A 0.2.5 value | Current application behavior |\n| --- | --- | --- | --- |\n| Accepted, not yet processing | **TASK_STATE_SUBMITTED** | **submitted** | Emitted for queued work |\n| Actively processing | **TASK_STATE_WORKING** | **working** | Emitted while the turn runs |\n| Waiting for a person | **TASK_STATE_INPUT_REQUIRED** | **input-required** | Emitted when a delegated user's approval-gated action pauses; retain this task and answer the pending decision |\n| Additional authentication required | **TASK_STATE_AUTH_REQUIRED** | **auth-required** | Protocol value understood, but not emitted by this application |\n| Completed successfully | **TASK_STATE_COMPLETED** | **completed** | Emitted as a terminal outcome |\n| Failed | **TASK_STATE_FAILED** | **failed** | Emitted as a terminal outcome, including abandoned execution recovery |\n| Cancelled | **TASK_STATE_CANCELED** | **canceled** | Emitted only when cancellation becomes the task outcome |\n| Rejected by the agent | **TASK_STATE_REJECTED** | **rejected** | Protocol value understood, but not emitted by this application |\n| State cannot be determined | **TASK_STATE_UNKNOWN** | **unknown** | Protocol value understood, but not emitted; an inaccessible task is reported as not found instead |\n\n**Input required is not a failure.** For a delegated user, it means the exact\nexecution has paused at an approval boundary. A machine principal cannot supply\nhuman approval, so the same protected action is denied instead of being parked\nindefinitely.\n\n## Complete one controlled exchange\n\n1. Load the selected agent card and record its environment, agent identity and\n chosen skill.\n2. Authenticate with a credential issued for that agent audience and the\n intended acting principal.\n3. Send one short text request in a non-production organization. State the\n desired result and boundaries rather than embedding credentials or large\n application records in the message.\n4. If the response completes immediately, validate its content and confirm any\n claimed application change against authoritative state.\n5. If a task is returned, store its task identifier, **contextId**, agent\n instance and acting identity together. Poll or stream using the same\n authorization context.\n6. Exercise one refused cross-identity or cross-agent task read. It should not\n reveal whether another caller's task exists.\n\n## Respect identity and ownership\n\nThe public agent card is metadata. Task operations require a Bearer credential\nwhose audience matches the selected agent. A delegated user or machine identity\nstill faces application roles, organization scope and per-operation policy.\nAnother caller's task is intentionally indistinguishable from a missing task.\n\nNamed agent instances have their own card, audience and skill subset. Keep the\nagent instance, task, conversation context and credential aligned throughout\nthe exchange.\n\nIf a task pauses for approval, present the proposed impact to the authorized\nperson and retain the pending task identity. Approval resumes that exact work;\nstarting a new conversation is not equivalent. If the work is no longer\nacceptable, cancel the task rather than approving and attempting to reverse it\nlater.\n\nCancellation is an outcome, not merely a request. Read the task after the\ncancellation attempt and distinguish a task that became cancelled from one that\nhad already completed or failed. Do not report success when cancellation was\nrefused because the task was terminal.\n\n## Operate within the published limits\n\nOnly text message parts are currently consumed; a message with no usable text\nfails. Turn rate limits and organization token budgets are different controls: a 429\nrequires pacing, while a 402 requires budget or entitlement resolution. A\nhigh-impact action may pause for explicit approval rather than fail.\n\nHandle these observations separately:\n\n- **429 rate limited:** stop parallel turns and follow the indicated delay;\n- **402 budget exceeded:** waiting briefly will not restore entitlement—resolve\n the applicable allowance or plan;\n- **task not found:** verify the caller, agent instance and task identifier, while\n preserving the intentional no-disclosure boundary for another caller's task;\n- **working with no live execution:** continue reading the task; the application\n reports abandoned work as failed rather than leaving it indefinitely active;\n- **input required:** keep the task identity and complete the required approval\n or input through the supported continuation path;\n- **terminal task:** do not cancel or resume it as if it were still active.\n\nFor asynchronous operation, choose polling, streaming or configured push\nnotification only when the published agent contract supports it. Treat a push\nnotification as a signal to read the task's authoritative state, and process\nnotifications idempotently.\n\nTreat every returned message and artifact as untrusted input. Retain correlation\nand outcome evidence, redact prompts and results before export, and use the\napplication's audit trail as the authoritative record of protected actions.\n\n## Close the task with proof\n\nRecord the environment, agent instance, skill, acting identity reference,\norganization, **contextId**, task identifier, state timeline and non-sensitive\ncorrelation evidence. Confirm the final application resource or external effect\ninstead of relying only on the agent's final message.\n\nIf the connection fails after submission, read the task under the original\nidentity before sending another message. Create new work only when the original\ntask is absent or terminal in a state that makes repetition deliberate and safe.\n\n## Protocol references for client implementers\n\n- The official [A2A 1.0 specification](https://a2a-protocol.org/latest/specification/)\n defines agent discovery, supported interfaces, messages, task lifecycle and\n the JSON-RPC binding.\n- [What changed in A2A 1.0](https://a2a-protocol.org/latest/whats-new-v1/)\n explains the move from scalar card transport/version fields to the ordered\n `supportedInterfaces` model.\n- The maintained [A2A protocol definitions](https://a2a-protocol.org/latest/definitions/)\n provide machine-readable schemas for clients and conformance tests.\n- [RFC 8707](https://www.rfc-editor.org/rfc/rfc8707.html) defines the resource\n indicator used to bind authorization to the selected agent audience.\n\nUse the specification to implement the chosen dialect, then use the live agent\ncard as the authority for this application’s URL, supported interfaces,\ncapabilities and skill inventory.\n\n## Continue safely\n\n- Return to [Agent integrations](/integrations/agents) to compare A2A with a\n structured MCP tool call.\n- **Connect an MCP client** — published in this section when the application\n exposes an MCP tool surface — when the desired work is a known application\n operation with an immediate structured result.\n- Use [Security and audit](/security-and-audit) to\n investigate protected actions independently of model output.";
419
424
  }];
420
425
  //# sourceMappingURL=application-consumer-documentation-content.techdoc.d.ts.map